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 "gimple.h"
29 : #include "predict.h"
30 : #include "stringpool.h"
31 : #include "tree-vrp.h"
32 : #include "tree-ssanames.h"
33 : #include "expmed.h"
34 : #include "memmodel.h"
35 : #include "optabs.h"
36 : #include "emit-rtl.h"
37 : #include "diagnostic-core.h"
38 : #include "fold-const.h"
39 : #include "internal-fn.h"
40 : #include "stor-layout.h"
41 : #include "dojump.h"
42 : #include "expr.h"
43 : #include "stringpool.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 5 : lookup_internal_fn (const char *name)
83 : {
84 5 : typedef hash_map<nofree_string_hash, internal_fn> name_to_fn_map_type;
85 5 : static name_to_fn_map_type *name_to_fn_map;
86 :
87 5 : if (!name_to_fn_map)
88 : {
89 3 : name_to_fn_map = new name_to_fn_map_type (IFN_LAST);
90 882 : for (unsigned int i = 0; i < IFN_LAST; ++i)
91 1758 : name_to_fn_map->put (internal_fn_name (internal_fn (i)),
92 879 : internal_fn (i));
93 : }
94 5 : internal_fn *entry = name_to_fn_map->get (name);
95 5 : 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 52398 : lookup_hilo_internal_fn (internal_fn ifn, internal_fn *lo, internal_fn *hi)
103 : {
104 52398 : gcc_assert (widening_fn_p (ifn));
105 :
106 52398 : 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 52398 : }
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 52398 : lookup_evenodd_internal_fn (internal_fn ifn, internal_fn *even,
125 : internal_fn *odd)
126 : {
127 52398 : gcc_assert (widening_fn_p (ifn));
128 :
129 52398 : 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 52398 : }
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 285405 : 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 285405 : internal_fn_fnspec_array[IFN_LAST] = 0;
155 285405 : }
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 90178 : 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 90178 : rtx dest = lhs_rtx;
219 90178 : if (dest && GET_CODE (dest) == SUBREG && SUBREG_PROMOTED_VAR_P (dest))
220 : dest = NULL_RTX;
221 90178 : create_output_operand (op, dest, mode);
222 90178 : }
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 90178 : assign_call_lhs (tree lhs, rtx lhs_rtx, expand_operand *op)
231 : {
232 90178 : 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 4334 : 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 4334 : else if (GET_MODE (lhs_rtx) == GET_MODE (op->value))
253 39 : emit_move_insn (lhs_rtx, op->value);
254 : else
255 : {
256 4295 : gcc_checking_assert (INTEGRAL_TYPE_P (TREE_TYPE (lhs)));
257 4295 : 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 80053 : expand_fn_using_insn (gcall *stmt, insn_code icode, unsigned int noutputs,
268 : unsigned int ninputs)
269 : {
270 80053 : gcc_assert (icode != CODE_FOR_nothing);
271 :
272 80053 : expand_operand *ops = XALLOCAVEC (expand_operand, noutputs + ninputs);
273 80053 : unsigned int opno = 0;
274 80053 : rtx lhs_rtx = NULL_RTX;
275 80053 : tree lhs = gimple_call_lhs (stmt);
276 :
277 80053 : if (noutputs)
278 : {
279 80053 : gcc_assert (noutputs == 1);
280 80053 : if (lhs)
281 80053 : lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
282 80053 : create_call_lhs_operand (&ops[opno], lhs_rtx,
283 80053 : insn_data[icode].operand[opno].mode);
284 80053 : opno += 1;
285 : }
286 : else
287 0 : gcc_assert (!lhs);
288 :
289 225302 : for (unsigned int i = 0; i < ninputs; ++i)
290 : {
291 145249 : tree rhs = gimple_call_arg (stmt, i);
292 145249 : tree rhs_type = TREE_TYPE (rhs);
293 145249 : rtx rhs_rtx = expand_normal (rhs);
294 145249 : if (INTEGRAL_TYPE_P (rhs_type))
295 7646 : create_convert_operand_from (&ops[opno], rhs_rtx,
296 7646 : TYPE_MODE (rhs_type),
297 7646 : TYPE_UNSIGNED (rhs_type));
298 137603 : else if (TREE_CODE (rhs) == SSA_NAME
299 112921 : && SSA_NAME_IS_DEFAULT_DEF (rhs)
300 142037 : && VAR_P (SSA_NAME_VAR (rhs)))
301 249 : create_undefined_input_operand (&ops[opno], TYPE_MODE (rhs_type));
302 57177 : else if (VECTOR_BOOLEAN_TYPE_P (rhs_type)
303 1531 : && SCALAR_INT_MODE_P (TYPE_MODE (rhs_type))
304 138885 : && maybe_ne (GET_MODE_PRECISION (TYPE_MODE (rhs_type)),
305 1531 : TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ()))
306 : {
307 : /* Ensure that the vector bitmasks do not have excess bits. */
308 432 : int nunits = TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ();
309 432 : rtx tmp = expand_binop (TYPE_MODE (rhs_type), and_optab, rhs_rtx,
310 432 : GEN_INT ((HOST_WIDE_INT_1U << nunits) - 1),
311 : NULL_RTX, true, OPTAB_WIDEN);
312 432 : create_input_operand (&ops[opno], tmp, TYPE_MODE (rhs_type));
313 : }
314 : else
315 136922 : create_input_operand (&ops[opno], rhs_rtx, TYPE_MODE (rhs_type));
316 145249 : opno += 1;
317 : }
318 :
319 80053 : gcc_assert (opno == noutputs + ninputs);
320 80053 : expand_insn (icode, opno, ops);
321 80053 : if (lhs_rtx)
322 80053 : assign_call_lhs (lhs, lhs_rtx, &ops[0]);
323 80053 : }
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 1479 : add_mask_else_and_len_args (expand_operand *ops, unsigned int opno, gcall *stmt)
345 : {
346 1479 : internal_fn ifn = gimple_call_internal_fn (stmt);
347 1479 : int len_index = internal_fn_len_index (ifn);
348 : /* BIAS is always consecutive next of LEN. */
349 1479 : int bias_index = len_index + 1;
350 1479 : int mask_index = internal_fn_mask_index (ifn);
351 :
352 : /* The order of arguments is always {mask, else, len, bias}. */
353 1479 : if (mask_index >= 0)
354 : {
355 1479 : tree mask = gimple_call_arg (stmt, mask_index);
356 1479 : rtx mask_rtx = expand_normal (mask);
357 :
358 1479 : tree mask_type = TREE_TYPE (mask);
359 1479 : if (VECTOR_BOOLEAN_TYPE_P (mask_type)
360 1479 : && SCALAR_INT_MODE_P (TYPE_MODE (mask_type))
361 2515 : && maybe_ne (GET_MODE_PRECISION (TYPE_MODE (mask_type)),
362 2294 : TYPE_VECTOR_SUBPARTS (mask_type).to_constant ()))
363 : {
364 : /* Ensure that the vector bitmasks do not have excess bits. */
365 221 : int nunits = TYPE_VECTOR_SUBPARTS (mask_type).to_constant ();
366 221 : mask_rtx = expand_binop (TYPE_MODE (mask_type), and_optab, mask_rtx,
367 221 : GEN_INT ((HOST_WIDE_INT_1U << nunits) - 1),
368 : NULL_RTX, true, OPTAB_WIDEN);
369 : }
370 :
371 1479 : create_input_operand (&ops[opno++], mask_rtx,
372 1479 : TYPE_MODE (TREE_TYPE (mask)));
373 : }
374 :
375 1479 : int els_index = internal_fn_else_index (ifn);
376 1479 : if (els_index >= 0)
377 : {
378 721 : tree els = gimple_call_arg (stmt, els_index);
379 721 : tree els_type = TREE_TYPE (els);
380 721 : if (TREE_CODE (els) == SSA_NAME
381 0 : && SSA_NAME_IS_DEFAULT_DEF (els)
382 721 : && VAR_P (SSA_NAME_VAR (els)))
383 0 : create_undefined_input_operand (&ops[opno++], TYPE_MODE (els_type));
384 : else
385 : {
386 721 : rtx els_rtx = expand_normal (els);
387 721 : create_input_operand (&ops[opno++], els_rtx, TYPE_MODE (els_type));
388 : }
389 : }
390 1479 : 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 1479 : 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 155782 : get_min_precision (tree arg, signop sign)
966 : {
967 155782 : int prec = TYPE_PRECISION (TREE_TYPE (arg));
968 155782 : int cnt = 0;
969 155782 : signop orig_sign = sign;
970 155782 : if (TREE_CODE (arg) == INTEGER_CST)
971 : {
972 40555 : int p;
973 40555 : if (TYPE_SIGN (TREE_TYPE (arg)) != sign)
974 : {
975 14465 : widest_int w = wi::to_widest (arg);
976 14465 : w = wi::ext (w, prec, sign);
977 14465 : p = wi::min_precision (w, sign);
978 14465 : }
979 : else
980 26090 : p = wi::min_precision (wi::to_wide (arg), sign);
981 40555 : return MIN (p, prec);
982 : }
983 115167 : while (CONVERT_EXPR_P (arg)
984 6563 : && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
985 128293 : && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
986 : {
987 6503 : arg = TREE_OPERAND (arg, 0);
988 6503 : if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
989 : {
990 342 : if (TYPE_UNSIGNED (TREE_TYPE (arg)))
991 : sign = UNSIGNED;
992 319 : else if (sign == UNSIGNED
993 319 : && (get_range_pos_neg (arg,
994 : currently_expanding_gimple_stmt)
995 : != 1))
996 0 : return prec + (orig_sign != sign);
997 342 : prec = TYPE_PRECISION (TREE_TYPE (arg));
998 : }
999 6503 : if (++cnt > 30)
1000 0 : return prec + (orig_sign != sign);
1001 : }
1002 115167 : if (CONVERT_EXPR_P (arg)
1003 60 : && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
1004 115287 : && 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 60 : int oprec = get_min_precision (TREE_OPERAND (arg, 0), sign);
1009 60 : if (oprec < prec)
1010 60 : return oprec + (orig_sign != sign);
1011 : }
1012 115167 : if (TREE_CODE (arg) != SSA_NAME)
1013 0 : return prec + (orig_sign != sign);
1014 115167 : int_range_max r;
1015 115167 : gimple *cg = currently_expanding_gimple_stmt;
1016 230663 : while (!get_range_query (cfun)->range_of_expr (r, arg, cg)
1017 115496 : || r.varying_p ()
1018 258114 : || r.undefined_p ())
1019 : {
1020 88375 : gimple *g = SSA_NAME_DEF_STMT (arg);
1021 88375 : if (is_gimple_assign (g)
1022 88375 : && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
1023 : {
1024 1319 : tree t = gimple_assign_rhs1 (g);
1025 2638 : if (INTEGRAL_TYPE_P (TREE_TYPE (t))
1026 1670 : && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
1027 : {
1028 329 : arg = t;
1029 329 : if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
1030 : {
1031 0 : if (TYPE_UNSIGNED (TREE_TYPE (arg)))
1032 : sign = UNSIGNED;
1033 0 : else if (sign == UNSIGNED
1034 0 : && get_range_pos_neg (arg, g) != 1)
1035 0 : return prec + (orig_sign != sign);
1036 0 : prec = TYPE_PRECISION (TREE_TYPE (arg));
1037 : }
1038 329 : if (++cnt > 30)
1039 0 : return prec + (orig_sign != sign);
1040 329 : continue;
1041 : }
1042 : }
1043 88046 : return prec + (orig_sign != sign);
1044 : }
1045 27121 : if (sign == TYPE_SIGN (TREE_TYPE (arg)))
1046 : {
1047 19833 : int p1 = wi::min_precision (r.lower_bound (), sign);
1048 19833 : int p2 = wi::min_precision (r.upper_bound (), sign);
1049 19833 : p1 = MAX (p1, p2);
1050 19833 : prec = MIN (prec, p1);
1051 : }
1052 14473 : else if (sign == UNSIGNED && !wi::neg_p (r.lower_bound (), SIGNED))
1053 : {
1054 7181 : int p = wi::min_precision (r.upper_bound (), UNSIGNED);
1055 7288 : prec = MIN (prec, p);
1056 : }
1057 27121 : return prec + (orig_sign != sign);
1058 115167 : }
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 80568 : expand_arith_set_overflow (tree lhs, rtx target)
1065 : {
1066 80568 : if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs))) == 1
1067 80568 : && !TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs))))
1068 194 : write_complex_part (target, constm1_rtx, true, false);
1069 : else
1070 80374 : write_complex_part (target, const1_rtx, true, false);
1071 80568 : }
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 71935 : expand_arith_overflow_result_store (tree lhs, rtx target,
1080 : scalar_int_mode mode, rtx res)
1081 : {
1082 71935 : scalar_int_mode tgtmode
1083 143870 : = as_a <scalar_int_mode> (GET_MODE_INNER (GET_MODE (target)));
1084 71935 : rtx lres = res;
1085 71935 : if (tgtmode != mode)
1086 : {
1087 17934 : rtx_code_label *done_label = gen_label_rtx ();
1088 17934 : int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
1089 17934 : lres = convert_modes (tgtmode, mode, res, uns);
1090 17934 : gcc_assert (GET_MODE_PRECISION (tgtmode) < GET_MODE_PRECISION (mode));
1091 17934 : 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 17934 : expand_arith_set_overflow (lhs, target);
1095 17934 : emit_label (done_label);
1096 : }
1097 71935 : int prec = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs)));
1098 71935 : int tgtprec = GET_MODE_PRECISION (tgtmode);
1099 71935 : if (prec < tgtprec)
1100 : {
1101 3543 : rtx_code_label *done_label = gen_label_rtx ();
1102 3543 : int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
1103 3543 : res = lres;
1104 3543 : 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 1535 : lres = expand_shift (LSHIFT_EXPR, tgtmode, res, tgtprec - prec,
1115 : NULL_RTX, 1);
1116 1535 : lres = expand_shift (RSHIFT_EXPR, tgtmode, lres, tgtprec - prec,
1117 : NULL_RTX, 0);
1118 : }
1119 3543 : do_compare_rtx_and_jump (res, lres,
1120 : EQ, true, tgtmode, NULL_RTX, NULL, done_label,
1121 : profile_probability::very_likely ());
1122 3543 : expand_arith_set_overflow (lhs, target);
1123 3543 : emit_label (done_label);
1124 : }
1125 71935 : write_complex_part (target, lres, false, false);
1126 71935 : }
1127 :
1128 : /* Helper for expand_*_overflow. Store RES into TARGET. */
1129 :
1130 : static void
1131 4659 : expand_ubsan_result_store (tree lhs, rtx target, scalar_int_mode mode,
1132 : rtx res, rtx_code_label *do_error)
1133 : {
1134 4659 : if (TREE_CODE (TREE_TYPE (lhs)) == BITINT_TYPE
1135 4659 : && 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 4659 : 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 4659 : emit_move_insn (target, res);
1171 4659 : }
1172 :
1173 : /* Add sub/add overflow checking to the statement STMT.
1174 : CODE says whether the operation is +, or -. */
1175 :
1176 : void
1177 39620 : 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 39620 : rtx res, target = NULL_RTX;
1182 39620 : tree fn;
1183 39620 : rtx_code_label *done_label = gen_label_rtx ();
1184 39620 : rtx_code_label *do_error = gen_label_rtx ();
1185 39620 : do_pending_stack_adjust ();
1186 39620 : rtx op0 = expand_normal (arg0);
1187 39620 : rtx op1 = expand_normal (arg1);
1188 39620 : scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg0));
1189 39620 : int prec = GET_MODE_PRECISION (mode);
1190 39620 : rtx sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
1191 39620 : bool do_xor = false;
1192 :
1193 39620 : if (is_ubsan)
1194 3386 : gcc_assert (!unsr_p && !uns0_p && !uns1_p);
1195 :
1196 39620 : if (lhs)
1197 : {
1198 39092 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
1199 39092 : if (!is_ubsan)
1200 36234 : 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 39620 : 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 38785 : if (uns0_p && uns1_p && unsr_p)
1274 : {
1275 21504 : insn_code icode = optab_handler (code == PLUS_EXPR ? uaddv4_optab
1276 : : usubv4_optab, mode);
1277 16064 : if (icode != CODE_FOR_nothing)
1278 : {
1279 15159 : class expand_operand ops[4];
1280 15159 : rtx_insn *last = get_last_insn ();
1281 :
1282 15159 : res = gen_reg_rtx (mode);
1283 15159 : create_output_operand (&ops[0], res, mode);
1284 15159 : create_input_operand (&ops[1], op0, mode);
1285 15159 : create_input_operand (&ops[2], op1, mode);
1286 15159 : create_fixed_operand (&ops[3], do_error);
1287 15159 : if (maybe_expand_insn (icode, 4, ops))
1288 : {
1289 15159 : last = get_last_insn ();
1290 15159 : if (profile_status_for_fn (cfun) != PROFILE_ABSENT
1291 12564 : && JUMP_P (last)
1292 12564 : && any_condjump_p (last)
1293 27723 : && !find_reg_note (last, REG_BR_PROB, 0))
1294 12564 : add_reg_br_prob_note (last,
1295 : profile_probability::very_unlikely ());
1296 15159 : emit_jump (done_label);
1297 15159 : 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 1810 : res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
1306 : op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
1307 905 : 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 905 : 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 905 : tem = op1;
1320 1810 : 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 905 : goto do_error_label;
1324 : }
1325 :
1326 : /* s1 +- u2 -> sr */
1327 23556 : if (!uns0_p && uns1_p && !unsr_p)
1328 : {
1329 : /* Compute the operation. On RTL level, the addition is always
1330 : unsigned. */
1331 2111 : res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
1332 : op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
1333 2111 : rtx tem = expand_binop (mode, add_optab,
1334 : code == PLUS_EXPR ? res : op0, sgn,
1335 : NULL_RTX, false, OPTAB_LIB_WIDEN);
1336 1309 : do_compare_rtx_and_jump (tem, op1, GEU, true, mode, NULL_RTX, NULL,
1337 : done_label, profile_probability::very_likely ());
1338 1309 : goto do_error_label;
1339 : }
1340 :
1341 : /* s1 + u2 -> ur */
1342 22247 : if (code == PLUS_EXPR && !uns0_p && uns1_p && unsr_p)
1343 : {
1344 1919 : 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 1919 : arg1 = error_mark_node;
1349 1919 : do_xor = true;
1350 1919 : goto do_signed;
1351 : }
1352 :
1353 : /* u1 - s2 -> ur */
1354 20328 : if (code == MINUS_EXPR && uns0_p && !uns1_p && unsr_p)
1355 : {
1356 820 : 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 820 : arg0 = error_mark_node;
1361 820 : do_xor = true;
1362 820 : goto do_signed;
1363 : }
1364 :
1365 : /* s1 - u2 -> ur */
1366 19508 : 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 1358 : res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
1371 : OPTAB_LIB_WIDEN);
1372 1358 : int pos_neg = get_range_pos_neg (arg0, currently_expanding_gimple_stmt);
1373 1358 : if (pos_neg == 2)
1374 : /* If ARG0 is known to be always negative, this is always overflow. */
1375 148 : emit_jump (do_error);
1376 1210 : else if (pos_neg == 3)
1377 : /* If ARG0 is not known to be always positive, check at runtime. */
1378 1210 : do_compare_rtx_and_jump (op0, const0_rtx, LT, false, mode, NULL_RTX,
1379 : NULL, do_error, profile_probability::very_unlikely ());
1380 1358 : do_compare_rtx_and_jump (op1, op0, LEU, true, mode, NULL_RTX, NULL,
1381 : done_label, profile_probability::very_likely ());
1382 1358 : goto do_error_label;
1383 : }
1384 :
1385 : /* u1 - s2 -> sr */
1386 18150 : 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 390 : res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
1391 : OPTAB_LIB_WIDEN);
1392 390 : rtx tem = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
1393 : OPTAB_LIB_WIDEN);
1394 390 : do_compare_rtx_and_jump (op0, tem, LTU, true, mode, NULL_RTX, NULL,
1395 : done_label, profile_probability::very_likely ());
1396 390 : goto do_error_label;
1397 : }
1398 :
1399 : /* u1 + u2 -> sr */
1400 17760 : 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 1393 : res = expand_binop (mode, add_optab, op0, op1, NULL_RTX, false,
1405 : OPTAB_LIB_WIDEN);
1406 1393 : do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX,
1407 : NULL, do_error, profile_probability::very_unlikely ());
1408 1393 : 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 1393 : if (prec <= BITS_PER_WORD
1417 1393 : ? (CONST_SCALAR_INT_P (op1) && REG_P (op0))
1418 448 : : CONST_SCALAR_INT_P (op0))
1419 1393 : tem = op0;
1420 1393 : do_compare_rtx_and_jump (res, tem, GEU, true, mode, NULL_RTX, NULL,
1421 : done_label, profile_probability::very_likely ());
1422 1393 : goto do_error_label;
1423 : }
1424 :
1425 : /* s1 +- s2 -> ur */
1426 16367 : if (!uns0_p && !uns1_p && unsr_p)
1427 : {
1428 : /* Compute the operation. On RTL level, the addition is always
1429 : unsigned. */
1430 3516 : res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
1431 : op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
1432 2359 : int pos_neg = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
1433 2359 : if (code == PLUS_EXPR)
1434 : {
1435 1202 : int pos_neg0 = get_range_pos_neg (arg0,
1436 : currently_expanding_gimple_stmt);
1437 1202 : if (pos_neg0 != 3 && pos_neg == 3)
1438 : {
1439 : std::swap (op0, op1);
1440 : pos_neg = pos_neg0;
1441 : }
1442 : }
1443 2290 : rtx tem;
1444 2290 : if (pos_neg != 3)
1445 : {
1446 1941 : 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 1161 : 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 1198 : rtx_code_label *do_ior_label = gen_label_rtx ();
1455 1620 : 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 1198 : tem = expand_binop (mode, and_optab, op0, res, NULL_RTX, false,
1460 : OPTAB_LIB_WIDEN);
1461 1198 : do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
1462 : NULL, done_label, profile_probability::very_likely ());
1463 1198 : emit_jump (do_error);
1464 1198 : emit_label (do_ior_label);
1465 1198 : tem = expand_binop (mode, ior_optab, op0, res, NULL_RTX, false,
1466 : OPTAB_LIB_WIDEN);
1467 1198 : do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
1468 : NULL, done_label, profile_probability::very_likely ());
1469 : }
1470 2359 : goto do_error_label;
1471 : }
1472 :
1473 : /* u1 - u2 -> sr */
1474 14008 : 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 1960 : res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
1479 : OPTAB_LIB_WIDEN);
1480 1960 : rtx_code_label *op0_geu_op1 = gen_label_rtx ();
1481 1960 : do_compare_rtx_and_jump (op0, op1, GEU, true, mode, NULL_RTX, NULL,
1482 : op0_geu_op1, profile_probability::even ());
1483 1960 : do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX,
1484 : NULL, done_label, profile_probability::very_likely ());
1485 1960 : emit_jump (do_error);
1486 1960 : emit_label (op0_geu_op1);
1487 1960 : do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
1488 : NULL, done_label, profile_probability::very_likely ());
1489 1960 : goto do_error_label;
1490 : }
1491 :
1492 12048 : gcc_assert (!uns0_p && !uns1_p && !unsr_p);
1493 :
1494 : /* s1 +- s2 -> sr */
1495 12048 : do_signed:
1496 14787 : {
1497 21411 : insn_code icode = optab_handler (code == PLUS_EXPR ? addv4_optab
1498 : : subv4_optab, mode);
1499 14787 : if (icode != CODE_FOR_nothing)
1500 : {
1501 14787 : class expand_operand ops[4];
1502 14787 : rtx_insn *last = get_last_insn ();
1503 :
1504 14787 : res = gen_reg_rtx (mode);
1505 14787 : create_output_operand (&ops[0], res, mode);
1506 14787 : create_input_operand (&ops[1], op0, mode);
1507 14787 : create_input_operand (&ops[2], op1, mode);
1508 14787 : create_fixed_operand (&ops[3], do_error);
1509 14787 : if (maybe_expand_insn (icode, 4, ops))
1510 : {
1511 14787 : last = get_last_insn ();
1512 14787 : if (profile_status_for_fn (cfun) != PROFILE_ABSENT
1513 9587 : && JUMP_P (last)
1514 9587 : && any_condjump_p (last)
1515 24374 : && !find_reg_note (last, REG_BR_PROB, 0))
1516 9587 : add_reg_br_prob_note (last,
1517 : profile_probability::very_unlikely ());
1518 14787 : emit_jump (done_label);
1519 14787 : 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 39620 : do_error_label:
1593 39620 : emit_label (do_error);
1594 39620 : if (is_ubsan)
1595 : {
1596 : /* Expand the ubsan builtin call. */
1597 3386 : push_temp_slots ();
1598 3386 : fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (arg0),
1599 : arg0, arg1, datap);
1600 3386 : expand_normal (fn);
1601 3386 : pop_temp_slots ();
1602 3386 : do_pending_stack_adjust ();
1603 : }
1604 36234 : else if (lhs)
1605 36234 : expand_arith_set_overflow (lhs, target);
1606 :
1607 : /* We're done. */
1608 39620 : emit_label (done_label);
1609 :
1610 39620 : if (lhs)
1611 : {
1612 39092 : if (is_ubsan)
1613 2858 : expand_ubsan_result_store (lhs, target, mode, res, do_error);
1614 : else
1615 : {
1616 36234 : if (do_xor)
1617 2739 : res = expand_binop (mode, add_optab, res, sgn, NULL_RTX, false,
1618 : OPTAB_LIB_WIDEN);
1619 :
1620 36234 : expand_arith_overflow_result_store (lhs, target, mode, res);
1621 : }
1622 : }
1623 39620 : }
1624 :
1625 : /* Add negate overflow checking to the statement STMT. */
1626 :
1627 : static void
1628 973 : expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan,
1629 : tree *datap)
1630 : {
1631 973 : rtx res, op1;
1632 973 : tree fn;
1633 973 : rtx_code_label *done_label, *do_error;
1634 973 : rtx target = NULL_RTX;
1635 :
1636 973 : done_label = gen_label_rtx ();
1637 973 : do_error = gen_label_rtx ();
1638 :
1639 973 : do_pending_stack_adjust ();
1640 973 : op1 = expand_normal (arg1);
1641 :
1642 973 : scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg1));
1643 973 : if (lhs)
1644 : {
1645 841 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
1646 841 : if (!is_ubsan)
1647 402 : write_complex_part (target, const0_rtx, true, false);
1648 : }
1649 :
1650 973 : enum insn_code icode = optab_handler (negv3_optab, mode);
1651 973 : if (icode != CODE_FOR_nothing)
1652 : {
1653 895 : class expand_operand ops[3];
1654 895 : rtx_insn *last = get_last_insn ();
1655 :
1656 895 : res = gen_reg_rtx (mode);
1657 895 : create_output_operand (&ops[0], res, mode);
1658 895 : create_input_operand (&ops[1], op1, mode);
1659 895 : create_fixed_operand (&ops[2], do_error);
1660 895 : if (maybe_expand_insn (icode, 3, ops))
1661 : {
1662 895 : last = get_last_insn ();
1663 895 : if (profile_status_for_fn (cfun) != PROFILE_ABSENT
1664 606 : && JUMP_P (last)
1665 606 : && any_condjump_p (last)
1666 1501 : && !find_reg_note (last, REG_BR_PROB, 0))
1667 606 : add_reg_br_prob_note (last,
1668 : profile_probability::very_unlikely ());
1669 895 : emit_jump (done_label);
1670 : }
1671 : else
1672 : {
1673 0 : delete_insns_since (last);
1674 0 : icode = CODE_FOR_nothing;
1675 : }
1676 : }
1677 :
1678 895 : 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 973 : emit_label (do_error);
1691 973 : if (is_ubsan)
1692 : {
1693 : /* Expand the ubsan builtin call. */
1694 571 : push_temp_slots ();
1695 571 : fn = ubsan_build_overflow_builtin (NEGATE_EXPR, loc, TREE_TYPE (arg1),
1696 : arg1, NULL_TREE, datap);
1697 571 : expand_normal (fn);
1698 571 : pop_temp_slots ();
1699 571 : do_pending_stack_adjust ();
1700 : }
1701 402 : else if (lhs)
1702 402 : expand_arith_set_overflow (lhs, target);
1703 :
1704 : /* We're done. */
1705 973 : emit_label (done_label);
1706 :
1707 973 : if (lhs)
1708 : {
1709 841 : if (is_ubsan)
1710 439 : 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 973 : }
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 18504 : 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 18504 : rtx res, op0, op1;
1753 18504 : tree fn, type;
1754 18504 : rtx_code_label *done_label, *do_error;
1755 18504 : rtx target = NULL_RTX;
1756 18504 : signop sign;
1757 18504 : enum insn_code icode;
1758 18504 : 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 18504 : flag_trapv = 0;
1763 18504 : done_label = gen_label_rtx ();
1764 18504 : do_error = gen_label_rtx ();
1765 :
1766 18504 : do_pending_stack_adjust ();
1767 18504 : op0 = expand_normal (arg0);
1768 18504 : op1 = expand_normal (arg1);
1769 :
1770 18504 : scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg0));
1771 18504 : bool uns = unsr_p;
1772 18504 : if (lhs)
1773 : {
1774 18360 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
1775 18360 : if (!is_ubsan)
1776 16998 : write_complex_part (target, const0_rtx, true, false);
1777 : }
1778 :
1779 17142 : if (is_ubsan)
1780 1506 : gcc_assert (!unsr_p && !uns0_p && !uns1_p);
1781 :
1782 : /* We assume both operands and result have the same precision
1783 : here (GET_MODE_BITSIZE (mode)), S stands for signed type
1784 : with that precision, U for unsigned type with that precision,
1785 : sgn for unsigned most significant bit in that precision.
1786 : s1 is signed first operand, u1 is unsigned first operand,
1787 : s2 is signed second operand, u2 is unsigned second operand,
1788 : sr is signed result, ur is unsigned result and the following
1789 : rules say how to compute result (which is always result of
1790 : the operands as if both were unsigned, cast to the right
1791 : signedness) and how to compute whether operation overflowed.
1792 : main_ovf (false) stands for jump on signed multiplication
1793 : overflow or the main algorithm with uns == false.
1794 : main_ovf (true) stands for jump on unsigned multiplication
1795 : overflow or the main algorithm with uns == true.
1796 :
1797 : s1 * s2 -> sr
1798 : res = (S) ((U) s1 * (U) s2)
1799 : ovf = main_ovf (false)
1800 : u1 * u2 -> ur
1801 : res = u1 * u2
1802 : ovf = main_ovf (true)
1803 : s1 * u2 -> ur
1804 : res = (U) s1 * u2
1805 : ovf = (s1 < 0 && u2) || main_ovf (true)
1806 : u1 * u2 -> sr
1807 : res = (S) (u1 * u2)
1808 : ovf = res < 0 || main_ovf (true)
1809 : s1 * u2 -> sr
1810 : res = (S) ((U) s1 * u2)
1811 : ovf = (S) u2 >= 0 ? main_ovf (false)
1812 : : (s1 != 0 && (s1 != -1 || u2 != (U) res))
1813 : s1 * s2 -> ur
1814 : t1 = (s1 & s2) < 0 ? (-(U) s1) : ((U) s1)
1815 : t2 = (s1 & s2) < 0 ? (-(U) s2) : ((U) s2)
1816 : res = t1 * t2
1817 : ovf = (s1 ^ s2) < 0 ? (s1 && s2) : main_ovf (true) */
1818 :
1819 18504 : if (uns0_p && !uns1_p)
1820 : {
1821 : /* Multiplication is commutative, if operand signedness differs,
1822 : canonicalize to the first operand being signed and second
1823 : unsigned to simplify following code. */
1824 1479 : std::swap (op0, op1);
1825 1479 : std::swap (arg0, arg1);
1826 1479 : uns0_p = false;
1827 1479 : uns1_p = true;
1828 : }
1829 :
1830 18504 : int pos_neg0 = get_range_pos_neg (arg0, currently_expanding_gimple_stmt);
1831 18504 : int pos_neg1 = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
1832 : /* Unsigned types with smaller than mode precision, even if they have most
1833 : significant bit set, are still zero-extended. */
1834 18504 : if (uns0_p && TYPE_PRECISION (TREE_TYPE (arg0)) < GET_MODE_PRECISION (mode))
1835 : pos_neg0 = 1;
1836 18504 : if (uns1_p && TYPE_PRECISION (TREE_TYPE (arg1)) < GET_MODE_PRECISION (mode))
1837 : pos_neg1 = 1;
1838 :
1839 : /* s1 * u2 -> ur */
1840 18504 : if (!uns0_p && uns1_p && unsr_p)
1841 : {
1842 2403 : switch (pos_neg0)
1843 : {
1844 0 : case 1:
1845 : /* If s1 is non-negative, just perform normal u1 * u2 -> ur. */
1846 1676 : goto do_main;
1847 531 : case 2:
1848 : /* If s1 is negative, avoid the main code, just multiply and
1849 : signal overflow if op1 is not 0. */
1850 531 : struct separate_ops ops;
1851 531 : ops.code = MULT_EXPR;
1852 531 : ops.type = TREE_TYPE (arg1);
1853 531 : ops.op0 = make_tree (ops.type, op0);
1854 531 : ops.op1 = make_tree (ops.type, op1);
1855 531 : ops.op2 = NULL_TREE;
1856 531 : ops.location = loc;
1857 531 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1858 531 : do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
1859 : NULL, done_label, profile_probability::very_likely ());
1860 727 : goto do_error_label;
1861 1872 : case 3:
1862 3744 : if (get_min_precision (arg1, UNSIGNED)
1863 1872 : + get_min_precision (arg0, SIGNED) <= GET_MODE_PRECISION (mode))
1864 : {
1865 : /* If the first operand is sign extended from narrower type, the
1866 : second operand is zero extended from narrower type and
1867 : the sum of the two precisions is smaller or equal to the
1868 : result precision: if the first argument is at runtime
1869 : non-negative, maximum result will be 0x7e81 or 0x7f..fe80..01
1870 : and there will be no overflow, if the first argument is
1871 : negative and the second argument zero, the result will be
1872 : 0 and there will be no overflow, if the first argument is
1873 : negative and the second argument positive, the result when
1874 : treated as signed will be negative (minimum -0x7f80 or
1875 : -0x7f..f80..0) there will be always overflow. So, do
1876 : res = (U) (s1 * u2)
1877 : ovf = (S) res < 0 */
1878 196 : struct separate_ops ops;
1879 196 : ops.code = MULT_EXPR;
1880 196 : ops.type
1881 196 : = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
1882 : 1);
1883 196 : ops.op0 = make_tree (ops.type, op0);
1884 196 : ops.op1 = make_tree (ops.type, op1);
1885 196 : ops.op2 = NULL_TREE;
1886 196 : ops.location = loc;
1887 196 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1888 196 : do_compare_rtx_and_jump (res, const0_rtx, GE, false,
1889 : mode, NULL_RTX, NULL, done_label,
1890 : profile_probability::very_likely ());
1891 196 : goto do_error_label;
1892 : }
1893 1676 : rtx_code_label *do_main_label;
1894 1676 : do_main_label = gen_label_rtx ();
1895 1676 : do_compare_rtx_and_jump (op0, const0_rtx, GE, false, mode, NULL_RTX,
1896 : NULL, do_main_label, profile_probability::very_likely ());
1897 1676 : do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
1898 : NULL, do_main_label, profile_probability::very_likely ());
1899 1676 : expand_arith_set_overflow (lhs, target);
1900 1676 : emit_label (do_main_label);
1901 1676 : goto do_main;
1902 0 : default:
1903 0 : gcc_unreachable ();
1904 : }
1905 : }
1906 :
1907 : /* u1 * u2 -> sr */
1908 16101 : if (uns0_p && uns1_p && !unsr_p)
1909 : {
1910 1490 : if ((pos_neg0 | pos_neg1) == 1)
1911 : {
1912 : /* If both arguments are zero extended from narrower types,
1913 : the MSB will be clear on both and so we can pretend it is
1914 : a normal s1 * s2 -> sr multiplication. */
1915 : uns0_p = false;
1916 : uns1_p = false;
1917 : }
1918 : else
1919 1037 : uns = true;
1920 : /* Rest of handling of this case after res is computed. */
1921 1490 : goto do_main;
1922 : }
1923 :
1924 : /* s1 * u2 -> sr */
1925 14611 : if (!uns0_p && uns1_p && !unsr_p)
1926 : {
1927 1553 : switch (pos_neg1)
1928 : {
1929 48 : case 1:
1930 1016 : goto do_main;
1931 537 : case 2:
1932 : /* If (S) u2 is negative (i.e. u2 is larger than maximum of S,
1933 : avoid the main code, just multiply and signal overflow
1934 : unless 0 * u2 or -1 * ((U) Smin). */
1935 537 : struct separate_ops ops;
1936 537 : ops.code = MULT_EXPR;
1937 537 : ops.type = TREE_TYPE (arg1);
1938 537 : ops.op0 = make_tree (ops.type, op0);
1939 537 : ops.op1 = make_tree (ops.type, op1);
1940 537 : ops.op2 = NULL_TREE;
1941 537 : ops.location = loc;
1942 537 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1943 537 : do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
1944 : NULL, done_label, profile_probability::very_likely ());
1945 537 : do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
1946 : NULL, do_error, profile_probability::very_unlikely ());
1947 537 : int prec;
1948 537 : prec = GET_MODE_PRECISION (mode);
1949 537 : rtx sgn;
1950 537 : sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
1951 537 : do_compare_rtx_and_jump (op1, sgn, EQ, true, mode, NULL_RTX,
1952 : NULL, done_label, profile_probability::very_likely ());
1953 537 : goto do_error_label;
1954 968 : case 3:
1955 : /* Rest of handling of this case after res is computed. */
1956 968 : goto do_main;
1957 0 : default:
1958 0 : gcc_unreachable ();
1959 : }
1960 : }
1961 :
1962 : /* s1 * s2 -> ur */
1963 13058 : if (!uns0_p && !uns1_p && unsr_p)
1964 : {
1965 2078 : rtx tem;
1966 2078 : switch (pos_neg0 | pos_neg1)
1967 : {
1968 0 : case 1: /* Both operands known to be non-negative. */
1969 0 : goto do_main;
1970 77 : case 2: /* Both operands known to be negative. */
1971 77 : op0 = expand_unop (mode, neg_optab, op0, NULL_RTX, false);
1972 77 : op1 = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
1973 : /* Avoid looking at arg0/arg1 ranges, as we've changed
1974 : the arguments. */
1975 77 : arg0 = error_mark_node;
1976 77 : arg1 = error_mark_node;
1977 77 : goto do_main;
1978 2001 : case 3:
1979 2001 : if ((pos_neg0 ^ pos_neg1) == 3)
1980 : {
1981 : /* If one operand is known to be negative and the other
1982 : non-negative, this overflows always, unless the non-negative
1983 : one is 0. Just do normal multiply and set overflow
1984 : unless one of the operands is 0. */
1985 0 : struct separate_ops ops;
1986 0 : ops.code = MULT_EXPR;
1987 0 : ops.type
1988 0 : = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
1989 : 1);
1990 0 : ops.op0 = make_tree (ops.type, op0);
1991 0 : ops.op1 = make_tree (ops.type, op1);
1992 0 : ops.op2 = NULL_TREE;
1993 0 : ops.location = loc;
1994 0 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1995 0 : do_compare_rtx_and_jump (pos_neg0 == 1 ? op0 : op1, const0_rtx, EQ,
1996 : true, mode, NULL_RTX, NULL, done_label,
1997 : profile_probability::very_likely ());
1998 0 : goto do_error_label;
1999 : }
2000 4002 : if (get_min_precision (arg0, SIGNED)
2001 2001 : + get_min_precision (arg1, SIGNED) <= GET_MODE_PRECISION (mode))
2002 : {
2003 : /* If both operands are sign extended from narrower types and
2004 : the sum of the two precisions is smaller or equal to the
2005 : result precision: if both arguments are at runtime
2006 : non-negative, maximum result will be 0x3f01 or 0x3f..f0..01
2007 : and there will be no overflow, if both arguments are negative,
2008 : maximum result will be 0x40..00 and there will be no overflow
2009 : either, if one argument is positive and the other argument
2010 : negative, the result when treated as signed will be negative
2011 : and there will be always overflow, and if one argument is
2012 : zero and the other negative the result will be zero and no
2013 : overflow. So, do
2014 : res = (U) (s1 * s2)
2015 : ovf = (S) res < 0 */
2016 225 : struct separate_ops ops;
2017 225 : ops.code = MULT_EXPR;
2018 225 : ops.type
2019 225 : = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
2020 : 1);
2021 225 : ops.op0 = make_tree (ops.type, op0);
2022 225 : ops.op1 = make_tree (ops.type, op1);
2023 225 : ops.op2 = NULL_TREE;
2024 225 : ops.location = loc;
2025 225 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2026 225 : do_compare_rtx_and_jump (res, const0_rtx, GE, false,
2027 : mode, NULL_RTX, NULL, done_label,
2028 : profile_probability::very_likely ());
2029 225 : goto do_error_label;
2030 : }
2031 : /* The general case, do all the needed comparisons at runtime. */
2032 1776 : rtx_code_label *do_main_label, *after_negate_label;
2033 1776 : rtx rop0, rop1;
2034 1776 : rop0 = gen_reg_rtx (mode);
2035 1776 : rop1 = gen_reg_rtx (mode);
2036 1776 : emit_move_insn (rop0, op0);
2037 1776 : emit_move_insn (rop1, op1);
2038 1776 : op0 = rop0;
2039 1776 : op1 = rop1;
2040 1776 : do_main_label = gen_label_rtx ();
2041 1776 : after_negate_label = gen_label_rtx ();
2042 1776 : tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false,
2043 : OPTAB_LIB_WIDEN);
2044 1776 : do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
2045 : NULL, after_negate_label, profile_probability::very_likely ());
2046 : /* Both arguments negative here, negate them and continue with
2047 : normal unsigned overflow checking multiplication. */
2048 1776 : emit_move_insn (op0, expand_unop (mode, neg_optab, op0,
2049 : NULL_RTX, false));
2050 1776 : emit_move_insn (op1, expand_unop (mode, neg_optab, op1,
2051 : NULL_RTX, false));
2052 : /* Avoid looking at arg0/arg1 ranges, as we might have changed
2053 : the arguments. */
2054 1776 : arg0 = error_mark_node;
2055 1776 : arg1 = error_mark_node;
2056 1776 : emit_jump (do_main_label);
2057 1776 : emit_label (after_negate_label);
2058 1776 : tem = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
2059 : OPTAB_LIB_WIDEN);
2060 1776 : do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
2061 : NULL, do_main_label,
2062 : profile_probability::very_likely ());
2063 : /* One argument is negative here, the other positive. This
2064 : overflows always, unless one of the arguments is 0. But
2065 : if e.g. s2 is 0, (U) s1 * 0 doesn't overflow, whatever s1
2066 : is, thus we can keep do_main code oring in overflow as is. */
2067 1776 : if (pos_neg0 != 2)
2068 1689 : do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
2069 : NULL, do_main_label,
2070 : profile_probability::very_unlikely ());
2071 1776 : if (pos_neg1 != 2)
2072 699 : do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
2073 : NULL, do_main_label,
2074 : profile_probability::very_unlikely ());
2075 1776 : expand_arith_set_overflow (lhs, target);
2076 1776 : emit_label (do_main_label);
2077 1776 : goto do_main;
2078 0 : default:
2079 0 : gcc_unreachable ();
2080 : }
2081 : }
2082 :
2083 10980 : do_main:
2084 17015 : type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode), uns);
2085 17015 : sign = uns ? UNSIGNED : SIGNED;
2086 17015 : icode = optab_handler (uns ? umulv4_optab : mulv4_optab, mode);
2087 17015 : if (uns
2088 10150 : && (integer_pow2p (arg0) || integer_pow2p (arg1))
2089 17881 : && (optimize_insn_for_speed_p () || icode == CODE_FOR_nothing))
2090 : {
2091 : /* Optimize unsigned multiplication by power of 2 constant
2092 : using 2 shifts, one for result, one to extract the shifted
2093 : out bits to see if they are all zero.
2094 : Don't do this if optimizing for size and we have umulv4_optab,
2095 : in that case assume multiplication will be shorter.
2096 : This is heuristics based on the single target that provides
2097 : umulv4 right now (i?86/x86_64), if further targets add it, this
2098 : might need to be revisited.
2099 : Cases where both operands are constant should be folded already
2100 : during GIMPLE, and cases where one operand is constant but not
2101 : power of 2 are questionable, either the WIDEN_MULT_EXPR case
2102 : below can be done without multiplication, just by shifts and adds,
2103 : or we'd need to divide the result (and hope it actually doesn't
2104 : really divide nor multiply) and compare the result of the division
2105 : with the original operand. */
2106 865 : rtx opn0 = op0;
2107 865 : rtx opn1 = op1;
2108 865 : tree argn0 = arg0;
2109 865 : tree argn1 = arg1;
2110 865 : if (integer_pow2p (arg0))
2111 : {
2112 0 : std::swap (opn0, opn1);
2113 0 : std::swap (argn0, argn1);
2114 : }
2115 865 : int cnt = tree_log2 (argn1);
2116 865 : if (cnt >= 0 && cnt < GET_MODE_PRECISION (mode))
2117 : {
2118 865 : rtx upper = const0_rtx;
2119 865 : res = expand_shift (LSHIFT_EXPR, mode, opn0, cnt, NULL_RTX, uns);
2120 865 : if (cnt != 0)
2121 693 : upper = expand_shift (RSHIFT_EXPR, mode, opn0,
2122 693 : GET_MODE_PRECISION (mode) - cnt,
2123 : NULL_RTX, uns);
2124 865 : do_compare_rtx_and_jump (upper, const0_rtx, EQ, true, mode,
2125 : NULL_RTX, NULL, done_label,
2126 : profile_probability::very_likely ());
2127 865 : goto do_error_label;
2128 : }
2129 : }
2130 16150 : if (icode != CODE_FOR_nothing)
2131 : {
2132 13229 : class expand_operand ops[4];
2133 13229 : rtx_insn *last = get_last_insn ();
2134 :
2135 13229 : res = gen_reg_rtx (mode);
2136 13229 : create_output_operand (&ops[0], res, mode);
2137 13229 : create_input_operand (&ops[1], op0, mode);
2138 13229 : create_input_operand (&ops[2], op1, mode);
2139 13229 : create_fixed_operand (&ops[3], do_error);
2140 13229 : if (maybe_expand_insn (icode, 4, ops))
2141 : {
2142 13229 : last = get_last_insn ();
2143 13229 : if (profile_status_for_fn (cfun) != PROFILE_ABSENT
2144 9037 : && JUMP_P (last)
2145 9037 : && any_condjump_p (last)
2146 22266 : && !find_reg_note (last, REG_BR_PROB, 0))
2147 9037 : add_reg_br_prob_note (last,
2148 : profile_probability::very_unlikely ());
2149 13229 : emit_jump (done_label);
2150 : }
2151 : else
2152 : {
2153 0 : delete_insns_since (last);
2154 0 : icode = CODE_FOR_nothing;
2155 : }
2156 : }
2157 :
2158 0 : if (icode == CODE_FOR_nothing)
2159 : {
2160 2921 : struct separate_ops ops;
2161 2921 : int prec = GET_MODE_PRECISION (mode);
2162 2921 : scalar_int_mode hmode, wmode;
2163 2921 : ops.op0 = make_tree (type, op0);
2164 2921 : ops.op1 = make_tree (type, op1);
2165 2921 : ops.op2 = NULL_TREE;
2166 2921 : ops.location = loc;
2167 :
2168 : /* Optimize unsigned overflow check where we don't use the
2169 : multiplication result, just whether overflow happened.
2170 : If we can do MULT_HIGHPART_EXPR, that followed by
2171 : comparison of the result against zero is cheapest.
2172 : We'll still compute res, but it should be DCEd later. */
2173 2921 : use_operand_p use;
2174 2921 : gimple *use_stmt;
2175 2921 : if (!is_ubsan
2176 2921 : && lhs
2177 2901 : && uns
2178 1859 : && !(uns0_p && uns1_p && !unsr_p)
2179 1574 : && can_mult_highpart_p (mode, uns) == 1
2180 0 : && single_imm_use (lhs, &use, &use_stmt)
2181 0 : && is_gimple_assign (use_stmt)
2182 2921 : && gimple_assign_rhs_code (use_stmt) == IMAGPART_EXPR)
2183 0 : goto highpart;
2184 :
2185 2921 : if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
2186 2921 : && targetm.scalar_mode_supported_p (wmode)
2187 0 : && can_widen_mult_without_libcall (wmode, mode, op0, op1, uns))
2188 : {
2189 0 : twoxwider:
2190 0 : ops.code = WIDEN_MULT_EXPR;
2191 0 : ops.type
2192 0 : = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), uns);
2193 :
2194 0 : res = expand_expr_real_2 (&ops, NULL_RTX, wmode, EXPAND_NORMAL);
2195 0 : rtx hipart = expand_shift (RSHIFT_EXPR, wmode, res, prec,
2196 : NULL_RTX, uns);
2197 0 : hipart = convert_modes (mode, wmode, hipart, uns);
2198 0 : res = convert_modes (mode, wmode, res, uns);
2199 0 : if (uns)
2200 : /* For the unsigned multiplication, there was overflow if
2201 : HIPART is non-zero. */
2202 0 : do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
2203 : NULL_RTX, NULL, done_label,
2204 : profile_probability::very_likely ());
2205 : else
2206 : {
2207 : /* RES is used more than once, place it in a pseudo. */
2208 0 : res = force_reg (mode, res);
2209 :
2210 0 : rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
2211 : NULL_RTX, 0);
2212 : /* RES is low half of the double width result, HIPART
2213 : the high half. There was overflow if
2214 : HIPART is different from RES < 0 ? -1 : 0. */
2215 0 : do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
2216 : NULL_RTX, NULL, done_label,
2217 : profile_probability::very_likely ());
2218 : }
2219 : }
2220 2921 : else if (can_mult_highpart_p (mode, uns) == 1)
2221 : {
2222 0 : highpart:
2223 0 : ops.code = MULT_HIGHPART_EXPR;
2224 0 : ops.type = type;
2225 :
2226 0 : rtx hipart = expand_expr_real_2 (&ops, NULL_RTX, mode,
2227 : EXPAND_NORMAL);
2228 0 : ops.code = MULT_EXPR;
2229 0 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2230 0 : if (uns)
2231 : /* For the unsigned multiplication, there was overflow if
2232 : HIPART is non-zero. */
2233 0 : do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
2234 : NULL_RTX, NULL, done_label,
2235 : profile_probability::very_likely ());
2236 : else
2237 : {
2238 0 : rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
2239 : NULL_RTX, 0);
2240 : /* RES is low half of the double width result, HIPART
2241 : the high half. There was overflow if
2242 : HIPART is different from RES < 0 ? -1 : 0. */
2243 0 : do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
2244 : NULL_RTX, NULL, done_label,
2245 : profile_probability::very_likely ());
2246 : }
2247 :
2248 : }
2249 2921 : else if (int_mode_for_size (prec / 2, 1).exists (&hmode)
2250 2921 : && 2 * GET_MODE_PRECISION (hmode) == prec)
2251 : {
2252 2921 : rtx_code_label *large_op0 = gen_label_rtx ();
2253 2921 : rtx_code_label *small_op0_large_op1 = gen_label_rtx ();
2254 2921 : rtx_code_label *one_small_one_large = gen_label_rtx ();
2255 2921 : rtx_code_label *both_ops_large = gen_label_rtx ();
2256 2921 : rtx_code_label *after_hipart_neg = uns ? NULL : gen_label_rtx ();
2257 1062 : rtx_code_label *after_lopart_neg = uns ? NULL : gen_label_rtx ();
2258 2921 : rtx_code_label *do_overflow = gen_label_rtx ();
2259 2921 : rtx_code_label *hipart_different = uns ? NULL : gen_label_rtx ();
2260 :
2261 2921 : unsigned int hprec = GET_MODE_PRECISION (hmode);
2262 2921 : rtx hipart0 = expand_shift (RSHIFT_EXPR, mode, op0, hprec,
2263 : NULL_RTX, uns);
2264 2921 : hipart0 = convert_modes (hmode, mode, hipart0, uns);
2265 2921 : rtx lopart0 = convert_modes (hmode, mode, op0, uns);
2266 2921 : rtx signbit0 = const0_rtx;
2267 2921 : if (!uns)
2268 1062 : signbit0 = expand_shift (RSHIFT_EXPR, hmode, lopart0, hprec - 1,
2269 : NULL_RTX, 0);
2270 2921 : rtx hipart1 = expand_shift (RSHIFT_EXPR, mode, op1, hprec,
2271 : NULL_RTX, uns);
2272 2921 : hipart1 = convert_modes (hmode, mode, hipart1, uns);
2273 2921 : rtx lopart1 = convert_modes (hmode, mode, op1, uns);
2274 2921 : rtx signbit1 = const0_rtx;
2275 2921 : if (!uns)
2276 1062 : signbit1 = expand_shift (RSHIFT_EXPR, hmode, lopart1, hprec - 1,
2277 : NULL_RTX, 0);
2278 :
2279 2921 : res = gen_reg_rtx (mode);
2280 :
2281 : /* True if op0 resp. op1 are known to be in the range of
2282 : halfstype. */
2283 2921 : bool op0_small_p = false;
2284 2921 : bool op1_small_p = false;
2285 : /* True if op0 resp. op1 are known to have all zeros or all ones
2286 : in the upper half of bits, but are not known to be
2287 : op{0,1}_small_p. */
2288 2921 : bool op0_medium_p = false;
2289 2921 : bool op1_medium_p = false;
2290 : /* -1 if op{0,1} is known to be negative, 0 if it is known to be
2291 : nonnegative, 1 if unknown. */
2292 2921 : int op0_sign = 1;
2293 2921 : int op1_sign = 1;
2294 :
2295 2921 : if (pos_neg0 == 1)
2296 : op0_sign = 0;
2297 2595 : else if (pos_neg0 == 2)
2298 299 : op0_sign = -1;
2299 2921 : if (pos_neg1 == 1)
2300 : op1_sign = 0;
2301 1634 : else if (pos_neg1 == 2)
2302 499 : op1_sign = -1;
2303 :
2304 2921 : unsigned int mprec0 = prec;
2305 2921 : if (arg0 != error_mark_node)
2306 2277 : mprec0 = get_min_precision (arg0, sign);
2307 2921 : if (mprec0 <= hprec)
2308 : op0_small_p = true;
2309 2673 : else if (!uns && mprec0 <= hprec + 1)
2310 2921 : op0_medium_p = true;
2311 2921 : unsigned int mprec1 = prec;
2312 2921 : if (arg1 != error_mark_node)
2313 2277 : mprec1 = get_min_precision (arg1, sign);
2314 2921 : if (mprec1 <= hprec)
2315 : op1_small_p = true;
2316 2227 : else if (!uns && mprec1 <= hprec + 1)
2317 2921 : op1_medium_p = true;
2318 :
2319 2921 : int smaller_sign = 1;
2320 2921 : int larger_sign = 1;
2321 2921 : if (op0_small_p)
2322 : {
2323 : smaller_sign = op0_sign;
2324 : larger_sign = op1_sign;
2325 : }
2326 2673 : else if (op1_small_p)
2327 : {
2328 : smaller_sign = op1_sign;
2329 : larger_sign = op0_sign;
2330 : }
2331 1979 : else if (op0_sign == op1_sign)
2332 : {
2333 923 : smaller_sign = op0_sign;
2334 923 : larger_sign = op0_sign;
2335 : }
2336 :
2337 2673 : if (!op0_small_p)
2338 2673 : do_compare_rtx_and_jump (signbit0, hipart0, NE, true, hmode,
2339 : NULL_RTX, NULL, large_op0,
2340 : profile_probability::unlikely ());
2341 :
2342 2921 : if (!op1_small_p)
2343 2227 : do_compare_rtx_and_jump (signbit1, hipart1, NE, true, hmode,
2344 : NULL_RTX, NULL, small_op0_large_op1,
2345 : profile_probability::unlikely ());
2346 :
2347 : /* If both op0 and op1 are sign (!uns) or zero (uns) extended from
2348 : hmode to mode, the multiplication will never overflow. We can
2349 : do just one hmode x hmode => mode widening multiplication. */
2350 2921 : tree halfstype = build_nonstandard_integer_type (hprec, uns);
2351 2921 : ops.op0 = make_tree (halfstype, lopart0);
2352 2921 : ops.op1 = make_tree (halfstype, lopart1);
2353 2921 : ops.code = WIDEN_MULT_EXPR;
2354 2921 : ops.type = type;
2355 2921 : rtx thisres
2356 2921 : = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2357 2921 : emit_move_insn (res, thisres);
2358 2921 : emit_jump (done_label);
2359 :
2360 2921 : emit_label (small_op0_large_op1);
2361 :
2362 : /* If op0 is sign (!uns) or zero (uns) extended from hmode to mode,
2363 : but op1 is not, just swap the arguments and handle it as op1
2364 : sign/zero extended, op0 not. */
2365 2921 : rtx larger = gen_reg_rtx (mode);
2366 2921 : rtx hipart = gen_reg_rtx (hmode);
2367 2921 : rtx lopart = gen_reg_rtx (hmode);
2368 2921 : emit_move_insn (larger, op1);
2369 2921 : emit_move_insn (hipart, hipart1);
2370 2921 : emit_move_insn (lopart, lopart0);
2371 2921 : emit_jump (one_small_one_large);
2372 :
2373 2921 : emit_label (large_op0);
2374 :
2375 2921 : if (!op1_small_p)
2376 2227 : do_compare_rtx_and_jump (signbit1, hipart1, NE, true, hmode,
2377 : NULL_RTX, NULL, both_ops_large,
2378 : profile_probability::unlikely ());
2379 :
2380 : /* If op1 is sign (!uns) or zero (uns) extended from hmode to mode,
2381 : but op0 is not, prepare larger, hipart and lopart pseudos and
2382 : handle it together with small_op0_large_op1. */
2383 2921 : emit_move_insn (larger, op0);
2384 2921 : emit_move_insn (hipart, hipart0);
2385 2921 : emit_move_insn (lopart, lopart1);
2386 :
2387 2921 : emit_label (one_small_one_large);
2388 :
2389 : /* lopart is the low part of the operand that is sign extended
2390 : to mode, larger is the other operand, hipart is the
2391 : high part of larger and lopart0 and lopart1 are the low parts
2392 : of both operands.
2393 : We perform lopart0 * lopart1 and lopart * hipart widening
2394 : multiplications. */
2395 2921 : tree halfutype = build_nonstandard_integer_type (hprec, 1);
2396 2921 : ops.op0 = make_tree (halfutype, lopart0);
2397 2921 : ops.op1 = make_tree (halfutype, lopart1);
2398 2921 : rtx lo0xlo1
2399 2921 : = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2400 :
2401 2921 : ops.op0 = make_tree (halfutype, lopart);
2402 2921 : ops.op1 = make_tree (halfutype, hipart);
2403 2921 : rtx loxhi = gen_reg_rtx (mode);
2404 2921 : rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2405 2921 : emit_move_insn (loxhi, tem);
2406 :
2407 2921 : if (!uns)
2408 : {
2409 : /* if (hipart < 0) loxhi -= lopart << (bitsize / 2); */
2410 1062 : if (larger_sign == 0)
2411 111 : emit_jump (after_hipart_neg);
2412 951 : else if (larger_sign != -1)
2413 946 : do_compare_rtx_and_jump (hipart, const0_rtx, GE, false, hmode,
2414 : NULL_RTX, NULL, after_hipart_neg,
2415 : profile_probability::even ());
2416 :
2417 1062 : tem = convert_modes (mode, hmode, lopart, 1);
2418 1062 : tem = expand_shift (LSHIFT_EXPR, mode, tem, hprec, NULL_RTX, 1);
2419 1062 : tem = expand_simple_binop (mode, MINUS, loxhi, tem, NULL_RTX,
2420 : 1, OPTAB_WIDEN);
2421 1062 : emit_move_insn (loxhi, tem);
2422 :
2423 1062 : emit_label (after_hipart_neg);
2424 :
2425 : /* if (lopart < 0) loxhi -= larger; */
2426 1062 : if (smaller_sign == 0)
2427 327 : emit_jump (after_lopart_neg);
2428 735 : else if (smaller_sign != -1)
2429 530 : do_compare_rtx_and_jump (lopart, const0_rtx, GE, false, hmode,
2430 : NULL_RTX, NULL, after_lopart_neg,
2431 : profile_probability::even ());
2432 :
2433 1062 : tem = expand_simple_binop (mode, MINUS, loxhi, larger, NULL_RTX,
2434 : 1, OPTAB_WIDEN);
2435 1062 : emit_move_insn (loxhi, tem);
2436 :
2437 1062 : emit_label (after_lopart_neg);
2438 : }
2439 :
2440 : /* loxhi += (uns) lo0xlo1 >> (bitsize / 2); */
2441 2921 : tem = expand_shift (RSHIFT_EXPR, mode, lo0xlo1, hprec, NULL_RTX, 1);
2442 2921 : tem = expand_simple_binop (mode, PLUS, loxhi, tem, NULL_RTX,
2443 : 1, OPTAB_WIDEN);
2444 2921 : emit_move_insn (loxhi, tem);
2445 :
2446 : /* if (loxhi >> (bitsize / 2)
2447 : == (hmode) loxhi >> (bitsize / 2 - 1)) (if !uns)
2448 : if (loxhi >> (bitsize / 2) == 0 (if uns). */
2449 2921 : rtx hipartloxhi = expand_shift (RSHIFT_EXPR, mode, loxhi, hprec,
2450 : NULL_RTX, 0);
2451 2921 : hipartloxhi = convert_modes (hmode, mode, hipartloxhi, 0);
2452 2921 : rtx signbitloxhi = const0_rtx;
2453 2921 : if (!uns)
2454 1062 : signbitloxhi = expand_shift (RSHIFT_EXPR, hmode,
2455 : convert_modes (hmode, mode,
2456 : loxhi, 0),
2457 1062 : hprec - 1, NULL_RTX, 0);
2458 :
2459 2921 : do_compare_rtx_and_jump (signbitloxhi, hipartloxhi, NE, true, hmode,
2460 : NULL_RTX, NULL, do_overflow,
2461 : profile_probability::very_unlikely ());
2462 :
2463 : /* res = (loxhi << (bitsize / 2)) | (hmode) lo0xlo1; */
2464 2921 : rtx loxhishifted = expand_shift (LSHIFT_EXPR, mode, loxhi, hprec,
2465 : NULL_RTX, 1);
2466 2921 : tem = convert_modes (mode, hmode,
2467 : convert_modes (hmode, mode, lo0xlo1, 1), 1);
2468 :
2469 2921 : tem = expand_simple_binop (mode, IOR, loxhishifted, tem, res,
2470 : 1, OPTAB_WIDEN);
2471 2921 : if (tem != res)
2472 0 : emit_move_insn (res, tem);
2473 2921 : emit_jump (done_label);
2474 :
2475 2921 : emit_label (both_ops_large);
2476 :
2477 : /* If both operands are large (not sign (!uns) or zero (uns)
2478 : extended from hmode), then perform the full multiplication
2479 : which will be the result of the operation.
2480 : The only cases which don't overflow are for signed multiplication
2481 : some cases where both hipart0 and highpart1 are 0 or -1.
2482 : For unsigned multiplication when high parts are both non-zero
2483 : this overflows always. */
2484 2921 : ops.code = MULT_EXPR;
2485 2921 : ops.op0 = make_tree (type, op0);
2486 2921 : ops.op1 = make_tree (type, op1);
2487 2921 : tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2488 2921 : emit_move_insn (res, tem);
2489 :
2490 2921 : if (!uns)
2491 : {
2492 1062 : if (!op0_medium_p)
2493 : {
2494 1062 : tem = expand_simple_binop (hmode, PLUS, hipart0, const1_rtx,
2495 : NULL_RTX, 1, OPTAB_WIDEN);
2496 1062 : do_compare_rtx_and_jump (tem, const1_rtx, GTU, true, hmode,
2497 : NULL_RTX, NULL, do_error,
2498 : profile_probability::very_unlikely ());
2499 : }
2500 :
2501 1062 : if (!op1_medium_p)
2502 : {
2503 1062 : tem = expand_simple_binop (hmode, PLUS, hipart1, const1_rtx,
2504 : NULL_RTX, 1, OPTAB_WIDEN);
2505 1062 : do_compare_rtx_and_jump (tem, const1_rtx, GTU, true, hmode,
2506 : NULL_RTX, NULL, do_error,
2507 : profile_probability::very_unlikely ());
2508 : }
2509 :
2510 : /* At this point hipart{0,1} are both in [-1, 0]. If they are
2511 : the same, overflow happened if res is non-positive, if they
2512 : are different, overflow happened if res is positive. */
2513 1062 : if (op0_sign != 1 && op1_sign != 1 && op0_sign != op1_sign)
2514 23 : emit_jump (hipart_different);
2515 1039 : else if (op0_sign == 1 || op1_sign == 1)
2516 937 : do_compare_rtx_and_jump (hipart0, hipart1, NE, true, hmode,
2517 : NULL_RTX, NULL, hipart_different,
2518 : profile_probability::even ());
2519 :
2520 1062 : do_compare_rtx_and_jump (res, const0_rtx, LE, false, mode,
2521 : NULL_RTX, NULL, do_error,
2522 : profile_probability::very_unlikely ());
2523 1062 : emit_jump (done_label);
2524 :
2525 1062 : emit_label (hipart_different);
2526 :
2527 1062 : do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode,
2528 : NULL_RTX, NULL, do_error,
2529 : profile_probability::very_unlikely ());
2530 1062 : emit_jump (done_label);
2531 : }
2532 :
2533 2921 : emit_label (do_overflow);
2534 :
2535 : /* Overflow, do full multiplication and fallthru into do_error. */
2536 2921 : ops.op0 = make_tree (type, op0);
2537 2921 : ops.op1 = make_tree (type, op1);
2538 2921 : tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2539 2921 : emit_move_insn (res, tem);
2540 : }
2541 0 : else if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
2542 0 : && targetm.scalar_mode_supported_p (wmode))
2543 : /* Even emitting a libcall is better than not detecting overflow
2544 : at all. */
2545 0 : goto twoxwider;
2546 : else
2547 : {
2548 0 : gcc_assert (!is_ubsan);
2549 0 : ops.code = MULT_EXPR;
2550 0 : ops.type = type;
2551 0 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2552 0 : emit_jump (done_label);
2553 : }
2554 : }
2555 :
2556 13229 : do_error_label:
2557 18504 : emit_label (do_error);
2558 18504 : if (is_ubsan)
2559 : {
2560 : /* Expand the ubsan builtin call. */
2561 1506 : push_temp_slots ();
2562 1506 : fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (arg0),
2563 : arg0, arg1, datap);
2564 1506 : expand_normal (fn);
2565 1506 : pop_temp_slots ();
2566 1506 : do_pending_stack_adjust ();
2567 : }
2568 16998 : else if (lhs)
2569 16998 : expand_arith_set_overflow (lhs, target);
2570 :
2571 : /* We're done. */
2572 18504 : emit_label (done_label);
2573 :
2574 : /* u1 * u2 -> sr */
2575 18504 : if (uns0_p && uns1_p && !unsr_p)
2576 : {
2577 1037 : rtx_code_label *all_done_label = gen_label_rtx ();
2578 1037 : do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
2579 : NULL, all_done_label, profile_probability::very_likely ());
2580 1037 : expand_arith_set_overflow (lhs, target);
2581 1037 : emit_label (all_done_label);
2582 : }
2583 :
2584 : /* s1 * u2 -> sr */
2585 18504 : if (!uns0_p && uns1_p && !unsr_p && pos_neg1 == 3)
2586 : {
2587 968 : rtx_code_label *all_done_label = gen_label_rtx ();
2588 968 : rtx_code_label *set_noovf = gen_label_rtx ();
2589 968 : do_compare_rtx_and_jump (op1, const0_rtx, GE, false, mode, NULL_RTX,
2590 : NULL, all_done_label, profile_probability::very_likely ());
2591 968 : expand_arith_set_overflow (lhs, target);
2592 968 : do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
2593 : NULL, set_noovf, profile_probability::very_likely ());
2594 968 : do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
2595 : NULL, all_done_label, profile_probability::very_unlikely ());
2596 968 : do_compare_rtx_and_jump (op1, res, NE, true, mode, NULL_RTX, NULL,
2597 : all_done_label, profile_probability::very_unlikely ());
2598 968 : emit_label (set_noovf);
2599 968 : write_complex_part (target, const0_rtx, true, false);
2600 968 : emit_label (all_done_label);
2601 : }
2602 :
2603 18504 : if (lhs)
2604 : {
2605 18360 : if (is_ubsan)
2606 1362 : expand_ubsan_result_store (lhs, target, mode, res, do_error);
2607 : else
2608 16998 : expand_arith_overflow_result_store (lhs, target, mode, res);
2609 : }
2610 18504 : flag_trapv = save_flag_trapv;
2611 18504 : }
2612 :
2613 : /* Expand UBSAN_CHECK_* internal function if it has vector operands. */
2614 :
2615 : static void
2616 549 : expand_vector_ubsan_overflow (location_t loc, enum tree_code code, tree lhs,
2617 : tree arg0, tree arg1)
2618 : {
2619 549 : poly_uint64 cnt = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0));
2620 549 : rtx_code_label *loop_lab = NULL;
2621 549 : rtx cntvar = NULL_RTX;
2622 549 : tree cntv = NULL_TREE;
2623 549 : tree eltype = TREE_TYPE (TREE_TYPE (arg0));
2624 549 : tree sz = TYPE_SIZE (eltype);
2625 549 : tree data = NULL_TREE;
2626 549 : tree resv = NULL_TREE;
2627 549 : rtx lhsr = NULL_RTX;
2628 549 : rtx resvr = NULL_RTX;
2629 549 : unsigned HOST_WIDE_INT const_cnt = 0;
2630 549 : bool use_loop_p = (!cnt.is_constant (&const_cnt) || const_cnt > 4);
2631 549 : int save_flag_trapv = flag_trapv;
2632 :
2633 : /* We don't want any __mulv?i3 etc. calls from the expansion of
2634 : these internal functions, so disable -ftrapv temporarily. */
2635 549 : flag_trapv = 0;
2636 549 : if (lhs)
2637 : {
2638 549 : optab op;
2639 549 : lhsr = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2640 141 : if (!VECTOR_MODE_P (GET_MODE (lhsr))
2641 408 : || (op = optab_for_tree_code (code, TREE_TYPE (arg0),
2642 : optab_default)) == unknown_optab
2643 957 : || (optab_handler (op, TYPE_MODE (TREE_TYPE (arg0)))
2644 : == CODE_FOR_nothing))
2645 : {
2646 141 : if (MEM_P (lhsr))
2647 141 : resv = make_tree (TREE_TYPE (lhs), lhsr);
2648 : else
2649 : {
2650 0 : resvr = assign_temp (TREE_TYPE (lhs), 1, 1);
2651 0 : resv = make_tree (TREE_TYPE (lhs), resvr);
2652 : }
2653 : }
2654 : }
2655 549 : if (use_loop_p)
2656 : {
2657 417 : do_pending_stack_adjust ();
2658 417 : loop_lab = gen_label_rtx ();
2659 417 : cntvar = gen_reg_rtx (TYPE_MODE (sizetype));
2660 417 : cntv = make_tree (sizetype, cntvar);
2661 417 : emit_move_insn (cntvar, const0_rtx);
2662 417 : emit_label (loop_lab);
2663 : }
2664 549 : if (TREE_CODE (arg0) != VECTOR_CST)
2665 : {
2666 461 : rtx arg0r = expand_normal (arg0);
2667 461 : arg0 = make_tree (TREE_TYPE (arg0), arg0r);
2668 : }
2669 549 : if (TREE_CODE (arg1) != VECTOR_CST)
2670 : {
2671 537 : rtx arg1r = expand_normal (arg1);
2672 537 : arg1 = make_tree (TREE_TYPE (arg1), arg1r);
2673 : }
2674 2154 : for (unsigned int i = 0; i < (use_loop_p ? 1 : const_cnt); i++)
2675 : {
2676 945 : tree op0, op1, res = NULL_TREE;
2677 945 : if (use_loop_p)
2678 : {
2679 417 : tree atype = build_array_type_nelts (eltype, cnt);
2680 417 : op0 = uniform_vector_p (arg0);
2681 417 : if (op0 == NULL_TREE)
2682 : {
2683 351 : op0 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg0);
2684 351 : op0 = build4_loc (loc, ARRAY_REF, eltype, op0, cntv,
2685 : NULL_TREE, NULL_TREE);
2686 : }
2687 417 : op1 = uniform_vector_p (arg1);
2688 417 : if (op1 == NULL_TREE)
2689 : {
2690 411 : op1 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg1);
2691 411 : op1 = build4_loc (loc, ARRAY_REF, eltype, op1, cntv,
2692 : NULL_TREE, NULL_TREE);
2693 : }
2694 417 : if (resv)
2695 : {
2696 141 : res = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, resv);
2697 141 : res = build4_loc (loc, ARRAY_REF, eltype, res, cntv,
2698 : NULL_TREE, NULL_TREE);
2699 : }
2700 : }
2701 : else
2702 : {
2703 528 : tree bitpos = bitsize_int (tree_to_uhwi (sz) * i);
2704 528 : op0 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg0, sz, bitpos);
2705 528 : op1 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg1, sz, bitpos);
2706 528 : if (resv)
2707 0 : res = fold_build3_loc (loc, BIT_FIELD_REF, eltype, resv, sz,
2708 : bitpos);
2709 : }
2710 945 : switch (code)
2711 : {
2712 317 : case PLUS_EXPR:
2713 317 : expand_addsub_overflow (loc, PLUS_EXPR, res, op0, op1,
2714 : false, false, false, true, &data);
2715 317 : break;
2716 462 : case MINUS_EXPR:
2717 462 : if (use_loop_p ? integer_zerop (arg0) : integer_zerop (op0))
2718 154 : expand_neg_overflow (loc, res, op1, true, &data);
2719 : else
2720 308 : expand_addsub_overflow (loc, MINUS_EXPR, res, op0, op1,
2721 : false, false, false, true, &data);
2722 : break;
2723 166 : case MULT_EXPR:
2724 166 : expand_mul_overflow (loc, res, op0, op1, false, false, false,
2725 : true, &data);
2726 166 : break;
2727 0 : default:
2728 0 : gcc_unreachable ();
2729 : }
2730 : }
2731 549 : if (use_loop_p)
2732 : {
2733 417 : struct separate_ops ops;
2734 417 : ops.code = PLUS_EXPR;
2735 417 : ops.type = TREE_TYPE (cntv);
2736 417 : ops.op0 = cntv;
2737 417 : ops.op1 = build_int_cst (TREE_TYPE (cntv), 1);
2738 417 : ops.op2 = NULL_TREE;
2739 417 : ops.location = loc;
2740 417 : rtx ret = expand_expr_real_2 (&ops, cntvar, TYPE_MODE (sizetype),
2741 : EXPAND_NORMAL);
2742 417 : if (ret != cntvar)
2743 0 : emit_move_insn (cntvar, ret);
2744 417 : rtx cntrtx = gen_int_mode (cnt, TYPE_MODE (sizetype));
2745 834 : do_compare_rtx_and_jump (cntvar, cntrtx, NE, false,
2746 417 : TYPE_MODE (sizetype), NULL_RTX, NULL, loop_lab,
2747 : profile_probability::very_likely ());
2748 : }
2749 549 : if (lhs && resv == NULL_TREE)
2750 : {
2751 408 : struct separate_ops ops;
2752 408 : ops.code = code;
2753 408 : ops.type = TREE_TYPE (arg0);
2754 408 : ops.op0 = arg0;
2755 408 : ops.op1 = arg1;
2756 408 : ops.op2 = NULL_TREE;
2757 408 : ops.location = loc;
2758 408 : rtx ret = expand_expr_real_2 (&ops, lhsr, TYPE_MODE (TREE_TYPE (arg0)),
2759 : EXPAND_NORMAL);
2760 408 : if (ret != lhsr)
2761 5 : emit_move_insn (lhsr, ret);
2762 : }
2763 141 : else if (resvr)
2764 0 : emit_move_insn (lhsr, resvr);
2765 549 : flag_trapv = save_flag_trapv;
2766 549 : }
2767 :
2768 : /* Expand UBSAN_CHECK_ADD call STMT. */
2769 :
2770 : static void
2771 1787 : expand_UBSAN_CHECK_ADD (internal_fn, gcall *stmt)
2772 : {
2773 1787 : location_t loc = gimple_location (stmt);
2774 1787 : tree lhs = gimple_call_lhs (stmt);
2775 1787 : tree arg0 = gimple_call_arg (stmt, 0);
2776 1787 : tree arg1 = gimple_call_arg (stmt, 1);
2777 1787 : if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
2778 185 : expand_vector_ubsan_overflow (loc, PLUS_EXPR, lhs, arg0, arg1);
2779 : else
2780 1602 : expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1,
2781 : false, false, false, true, NULL);
2782 1787 : }
2783 :
2784 : /* Expand UBSAN_CHECK_SUB call STMT. */
2785 :
2786 : static void
2787 1840 : expand_UBSAN_CHECK_SUB (internal_fn, gcall *stmt)
2788 : {
2789 1840 : location_t loc = gimple_location (stmt);
2790 1840 : tree lhs = gimple_call_lhs (stmt);
2791 1840 : tree arg0 = gimple_call_arg (stmt, 0);
2792 1840 : tree arg1 = gimple_call_arg (stmt, 1);
2793 1840 : if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
2794 264 : expand_vector_ubsan_overflow (loc, MINUS_EXPR, lhs, arg0, arg1);
2795 1576 : else if (integer_zerop (arg0))
2796 417 : expand_neg_overflow (loc, lhs, arg1, true, NULL);
2797 : else
2798 1159 : expand_addsub_overflow (loc, MINUS_EXPR, lhs, arg0, arg1,
2799 : false, false, false, true, NULL);
2800 1840 : }
2801 :
2802 : /* Expand UBSAN_CHECK_MUL call STMT. */
2803 :
2804 : static void
2805 1440 : expand_UBSAN_CHECK_MUL (internal_fn, gcall *stmt)
2806 : {
2807 1440 : location_t loc = gimple_location (stmt);
2808 1440 : tree lhs = gimple_call_lhs (stmt);
2809 1440 : tree arg0 = gimple_call_arg (stmt, 0);
2810 1440 : tree arg1 = gimple_call_arg (stmt, 1);
2811 1440 : if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
2812 100 : expand_vector_ubsan_overflow (loc, MULT_EXPR, lhs, arg0, arg1);
2813 : else
2814 1340 : expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true,
2815 : NULL);
2816 1440 : }
2817 :
2818 : /* Helper function for {ADD,SUB,MUL}_OVERFLOW call stmt expansion. */
2819 :
2820 : static void
2821 71711 : expand_arith_overflow (enum tree_code code, gimple *stmt)
2822 : {
2823 71711 : tree lhs = gimple_call_lhs (stmt);
2824 71711 : if (lhs == NULL_TREE)
2825 : return;
2826 71711 : tree arg0 = gimple_call_arg (stmt, 0);
2827 71711 : tree arg1 = gimple_call_arg (stmt, 1);
2828 71711 : tree type = TREE_TYPE (TREE_TYPE (lhs));
2829 71711 : int uns0_p = TYPE_UNSIGNED (TREE_TYPE (arg0));
2830 71711 : int uns1_p = TYPE_UNSIGNED (TREE_TYPE (arg1));
2831 71711 : int unsr_p = TYPE_UNSIGNED (type);
2832 71711 : int prec0 = TYPE_PRECISION (TREE_TYPE (arg0));
2833 71711 : int prec1 = TYPE_PRECISION (TREE_TYPE (arg1));
2834 71711 : int precres = TYPE_PRECISION (type);
2835 71711 : location_t loc = gimple_location (stmt);
2836 71711 : if (!uns0_p && get_range_pos_neg (arg0, stmt) == 1)
2837 : uns0_p = true;
2838 71711 : if (!uns1_p && get_range_pos_neg (arg1, stmt) == 1)
2839 : uns1_p = true;
2840 103428 : int pr = get_min_precision (arg0, uns0_p ? UNSIGNED : SIGNED);
2841 71711 : prec0 = MIN (prec0, pr);
2842 94737 : pr = get_min_precision (arg1, uns1_p ? UNSIGNED : SIGNED);
2843 71711 : prec1 = MIN (prec1, pr);
2844 71711 : int save_flag_trapv = flag_trapv;
2845 :
2846 : /* We don't want any __mulv?i3 etc. calls from the expansion of
2847 : these internal functions, so disable -ftrapv temporarily. */
2848 71711 : flag_trapv = 0;
2849 : /* If uns0_p && uns1_p, precop is minimum needed precision
2850 : of unsigned type to hold the exact result, otherwise
2851 : precop is minimum needed precision of signed type to
2852 : hold the exact result. */
2853 71711 : int precop;
2854 71711 : if (code == MULT_EXPR)
2855 23231 : precop = prec0 + prec1 + (uns0_p != uns1_p);
2856 : else
2857 : {
2858 48480 : if (uns0_p == uns1_p)
2859 31143 : precop = MAX (prec0, prec1) + 1;
2860 17337 : else if (uns0_p)
2861 6123 : precop = MAX (prec0 + 1, prec1) + 1;
2862 : else
2863 11214 : precop = MAX (prec0, prec1 + 1) + 1;
2864 : }
2865 71711 : int orig_precres = precres;
2866 :
2867 90257 : do
2868 : {
2869 90257 : if ((uns0_p && uns1_p)
2870 90257 : ? ((precop + !unsr_p) <= precres
2871 : /* u1 - u2 -> ur can overflow, no matter what precision
2872 : the result has. */
2873 35631 : && (code != MINUS_EXPR || !unsr_p))
2874 54626 : : (!unsr_p && precop <= precres))
2875 : {
2876 : /* The infinity precision result will always fit into result. */
2877 18301 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2878 18301 : write_complex_part (target, const0_rtx, true, false);
2879 18301 : scalar_int_mode mode = SCALAR_INT_TYPE_MODE (type);
2880 18301 : struct separate_ops ops;
2881 18301 : ops.code = code;
2882 18301 : ops.type = type;
2883 18301 : ops.op0 = fold_convert_loc (loc, type, arg0);
2884 18301 : ops.op1 = fold_convert_loc (loc, type, arg1);
2885 18301 : ops.op2 = NULL_TREE;
2886 18301 : ops.location = loc;
2887 18301 : rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2888 18301 : expand_arith_overflow_result_store (lhs, target, mode, tem);
2889 18301 : flag_trapv = save_flag_trapv;
2890 18301 : return;
2891 : }
2892 :
2893 : /* For operations with low precision, if target doesn't have them, start
2894 : with precres widening right away, otherwise do it only if the most
2895 : simple cases can't be used. */
2896 71956 : const int min_precision = targetm.min_arithmetic_precision ();
2897 71956 : if (orig_precres == precres && precres < min_precision)
2898 : ;
2899 70693 : else if ((uns0_p && uns1_p && unsr_p && prec0 <= precres
2900 21427 : && prec1 <= precres)
2901 49269 : || ((!uns0_p || !uns1_p) && !unsr_p
2902 19221 : && prec0 + uns0_p <= precres
2903 16440 : && prec1 + uns1_p <= precres))
2904 : {
2905 34378 : arg0 = fold_convert_loc (loc, type, arg0);
2906 34378 : arg1 = fold_convert_loc (loc, type, arg1);
2907 34378 : switch (code)
2908 : {
2909 10179 : case MINUS_EXPR:
2910 10179 : if (integer_zerop (arg0) && !unsr_p)
2911 : {
2912 402 : expand_neg_overflow (loc, lhs, arg1, false, NULL);
2913 402 : flag_trapv = save_flag_trapv;
2914 402 : return;
2915 : }
2916 : /* FALLTHRU */
2917 24502 : case PLUS_EXPR:
2918 24502 : expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
2919 : unsr_p, unsr_p, false, NULL);
2920 24502 : flag_trapv = save_flag_trapv;
2921 24502 : return;
2922 9474 : case MULT_EXPR:
2923 9474 : expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
2924 : unsr_p, unsr_p, false, NULL);
2925 9474 : flag_trapv = save_flag_trapv;
2926 9474 : return;
2927 0 : default:
2928 0 : gcc_unreachable ();
2929 : }
2930 : }
2931 :
2932 : /* For sub-word operations, retry with a wider type first. */
2933 37579 : if (orig_precres == precres && precop <= BITS_PER_WORD)
2934 : {
2935 19641 : int p = MAX (min_precision, precop);
2936 19641 : scalar_int_mode m = smallest_int_mode_for_size (p).require ();
2937 19641 : tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
2938 : uns0_p && uns1_p
2939 19641 : && unsr_p);
2940 19641 : p = TYPE_PRECISION (optype);
2941 19641 : if (p > precres)
2942 : {
2943 17988 : precres = p;
2944 17988 : unsr_p = TYPE_UNSIGNED (optype);
2945 17988 : type = optype;
2946 17988 : continue;
2947 : }
2948 : }
2949 :
2950 19590 : if (prec0 <= precres && prec1 <= precres)
2951 : {
2952 19032 : tree types[2];
2953 19032 : if (unsr_p)
2954 : {
2955 10937 : types[0] = build_nonstandard_integer_type (precres, 0);
2956 10937 : types[1] = type;
2957 : }
2958 : else
2959 : {
2960 8095 : types[0] = type;
2961 8095 : types[1] = build_nonstandard_integer_type (precres, 1);
2962 : }
2963 19032 : arg0 = fold_convert_loc (loc, types[uns0_p], arg0);
2964 19032 : arg1 = fold_convert_loc (loc, types[uns1_p], arg1);
2965 19032 : if (code != MULT_EXPR)
2966 11508 : expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
2967 : uns0_p, uns1_p, false, NULL);
2968 : else
2969 7524 : expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
2970 : uns0_p, uns1_p, false, NULL);
2971 19032 : flag_trapv = save_flag_trapv;
2972 19032 : return;
2973 : }
2974 :
2975 : /* Retry with a wider type. */
2976 558 : if (orig_precres == precres)
2977 : {
2978 558 : int p = MAX (prec0, prec1);
2979 558 : scalar_int_mode m = smallest_int_mode_for_size (p).require ();
2980 558 : tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
2981 : uns0_p && uns1_p
2982 558 : && unsr_p);
2983 558 : p = TYPE_PRECISION (optype);
2984 558 : if (p > precres)
2985 : {
2986 558 : precres = p;
2987 558 : unsr_p = TYPE_UNSIGNED (optype);
2988 558 : type = optype;
2989 558 : continue;
2990 : }
2991 : }
2992 :
2993 0 : gcc_unreachable ();
2994 : }
2995 : while (1);
2996 : }
2997 :
2998 : /* Expand ADD_OVERFLOW STMT. */
2999 :
3000 : static void
3001 25036 : expand_ADD_OVERFLOW (internal_fn, gcall *stmt)
3002 : {
3003 25036 : expand_arith_overflow (PLUS_EXPR, stmt);
3004 25036 : }
3005 :
3006 : /* Expand SUB_OVERFLOW STMT. */
3007 :
3008 : static void
3009 23444 : expand_SUB_OVERFLOW (internal_fn, gcall *stmt)
3010 : {
3011 23444 : expand_arith_overflow (MINUS_EXPR, stmt);
3012 23444 : }
3013 :
3014 : /* Expand MUL_OVERFLOW STMT. */
3015 :
3016 : static void
3017 23231 : expand_MUL_OVERFLOW (internal_fn, gcall *stmt)
3018 : {
3019 23231 : expand_arith_overflow (MULT_EXPR, stmt);
3020 23231 : }
3021 :
3022 : /* Expand UADDC STMT. */
3023 :
3024 : static void
3025 15132 : expand_UADDC (internal_fn ifn, gcall *stmt)
3026 : {
3027 15132 : tree lhs = gimple_call_lhs (stmt);
3028 15132 : tree arg1 = gimple_call_arg (stmt, 0);
3029 15132 : tree arg2 = gimple_call_arg (stmt, 1);
3030 15132 : tree arg3 = gimple_call_arg (stmt, 2);
3031 15132 : tree type = TREE_TYPE (arg1);
3032 15132 : machine_mode mode = TYPE_MODE (type);
3033 21253 : insn_code icode = optab_handler (ifn == IFN_UADDC
3034 : ? uaddc5_optab : usubc5_optab, mode);
3035 15132 : rtx op1 = expand_normal (arg1);
3036 15132 : rtx op2 = expand_normal (arg2);
3037 15132 : rtx op3 = expand_normal (arg3);
3038 15132 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3039 15132 : rtx re = gen_reg_rtx (mode);
3040 15132 : rtx im = gen_reg_rtx (mode);
3041 15132 : class expand_operand ops[5];
3042 15132 : create_output_operand (&ops[0], re, mode);
3043 15132 : create_output_operand (&ops[1], im, mode);
3044 15132 : create_input_operand (&ops[2], op1, mode);
3045 15132 : create_input_operand (&ops[3], op2, mode);
3046 15132 : create_input_operand (&ops[4], op3, mode);
3047 15132 : expand_insn (icode, 5, ops);
3048 15132 : write_complex_part (target, re, false, false);
3049 15132 : write_complex_part (target, im, true, false);
3050 15132 : }
3051 :
3052 : /* Expand USUBC STMT. */
3053 :
3054 : static void
3055 6121 : expand_USUBC (internal_fn ifn, gcall *stmt)
3056 : {
3057 6121 : expand_UADDC (ifn, stmt);
3058 6121 : }
3059 :
3060 : /* This should get folded in tree-vectorizer.cc. */
3061 :
3062 : static void
3063 0 : expand_LOOP_VECTORIZED (internal_fn, gcall *)
3064 : {
3065 0 : gcc_unreachable ();
3066 : }
3067 :
3068 : /* This should get folded in tree-vectorizer.cc. */
3069 :
3070 : static void
3071 0 : expand_LOOP_DIST_ALIAS (internal_fn, gcall *)
3072 : {
3073 0 : gcc_unreachable ();
3074 : }
3075 :
3076 : /* Return a memory reference of type TYPE for argument INDEX of STMT.
3077 : Use argument INDEX + 1 to derive the second (TBAA) operand. */
3078 :
3079 : static tree
3080 1479 : expand_call_mem_ref (tree type, gcall *stmt, int index)
3081 : {
3082 1479 : tree addr = gimple_call_arg (stmt, index);
3083 1479 : tree alias_ptr_type = TREE_TYPE (gimple_call_arg (stmt, index + 1));
3084 1479 : unsigned int align = tree_to_shwi (gimple_call_arg (stmt, index + 1));
3085 1479 : if (TYPE_ALIGN (type) != align)
3086 1213 : type = build_aligned_type (type, align);
3087 :
3088 1479 : tree tmp = addr;
3089 1479 : if (TREE_CODE (tmp) == SSA_NAME)
3090 : {
3091 1349 : gimple *def = get_gimple_for_ssa_name (tmp);
3092 1349 : if (def && gimple_assign_single_p (def))
3093 598 : tmp = gimple_assign_rhs1 (def);
3094 : }
3095 :
3096 1479 : if (TREE_CODE (tmp) == ADDR_EXPR)
3097 : {
3098 728 : tree mem = TREE_OPERAND (tmp, 0);
3099 728 : if (TREE_CODE (mem) == TARGET_MEM_REF
3100 728 : && types_compatible_p (TREE_TYPE (mem), type))
3101 : {
3102 598 : tree offset = TMR_OFFSET (mem);
3103 598 : if (type != TREE_TYPE (mem)
3104 144 : || alias_ptr_type != TREE_TYPE (offset)
3105 742 : || !integer_zerop (offset))
3106 : {
3107 481 : mem = copy_node (mem);
3108 962 : TMR_OFFSET (mem) = wide_int_to_tree (alias_ptr_type,
3109 481 : wi::to_poly_wide (offset));
3110 481 : TREE_TYPE (mem) = type;
3111 : }
3112 598 : return mem;
3113 : }
3114 : }
3115 :
3116 881 : return fold_build2 (MEM_REF, type, addr, build_int_cst (alias_ptr_type, 0));
3117 : }
3118 :
3119 : /* Expand MASK_LOAD{,_LANES}, MASK_LEN_LOAD or LEN_LOAD call STMT using optab
3120 : * OPTAB. */
3121 :
3122 : static void
3123 721 : expand_partial_load_optab_fn (internal_fn ifn, gcall *stmt, convert_optab optab)
3124 : {
3125 721 : int i = 0;
3126 721 : class expand_operand ops[6];
3127 721 : tree type, lhs, rhs, maskt;
3128 721 : rtx mem, target;
3129 721 : insn_code icode;
3130 :
3131 721 : maskt = gimple_call_arg (stmt, internal_fn_mask_index (ifn));
3132 721 : lhs = gimple_call_lhs (stmt);
3133 721 : if (lhs == NULL_TREE)
3134 0 : return;
3135 721 : type = TREE_TYPE (lhs);
3136 721 : rhs = expand_call_mem_ref (type, stmt, 0);
3137 :
3138 721 : if (optab == vec_mask_load_lanes_optab
3139 721 : || optab == vec_mask_len_load_lanes_optab)
3140 0 : icode = get_multi_vector_move (type, optab);
3141 721 : else if (optab == len_load_optab)
3142 0 : icode = direct_optab_handler (optab, TYPE_MODE (type));
3143 : else
3144 721 : icode = convert_optab_handler (optab, TYPE_MODE (type),
3145 721 : TYPE_MODE (TREE_TYPE (maskt)));
3146 :
3147 721 : mem = expand_expr (rhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3148 721 : gcc_assert (MEM_P (mem));
3149 : /* The built MEM_REF does not accurately reflect that the load
3150 : is only partial. Clear it. */
3151 721 : set_mem_expr (mem, NULL_TREE);
3152 721 : clear_mem_offset (mem);
3153 721 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3154 721 : create_call_lhs_operand (&ops[i++], target, TYPE_MODE (type));
3155 721 : create_fixed_operand (&ops[i++], mem);
3156 721 : i = add_mask_else_and_len_args (ops, i, stmt);
3157 721 : expand_insn (icode, i, ops);
3158 :
3159 721 : assign_call_lhs (lhs, target, &ops[0]);
3160 : }
3161 :
3162 : #define expand_mask_load_optab_fn expand_partial_load_optab_fn
3163 : #define expand_mask_load_lanes_optab_fn expand_mask_load_optab_fn
3164 : #define expand_len_load_optab_fn expand_partial_load_optab_fn
3165 : #define expand_mask_len_load_optab_fn expand_partial_load_optab_fn
3166 :
3167 : /* Expand MASK_STORE{,_LANES}, MASK_LEN_STORE or LEN_STORE call STMT using optab
3168 : * OPTAB. */
3169 :
3170 : static void
3171 758 : expand_partial_store_optab_fn (internal_fn ifn, gcall *stmt, convert_optab optab)
3172 : {
3173 758 : int i = 0;
3174 758 : class expand_operand ops[5];
3175 758 : tree type, lhs, rhs, maskt;
3176 758 : rtx mem, reg;
3177 758 : insn_code icode;
3178 :
3179 758 : maskt = gimple_call_arg (stmt, internal_fn_mask_index (ifn));
3180 758 : rhs = gimple_call_arg (stmt, internal_fn_stored_value_index (ifn));
3181 758 : type = TREE_TYPE (rhs);
3182 758 : lhs = expand_call_mem_ref (type, stmt, 0);
3183 :
3184 758 : if (optab == vec_mask_store_lanes_optab
3185 758 : || optab == vec_mask_len_store_lanes_optab)
3186 0 : icode = get_multi_vector_move (type, optab);
3187 758 : else if (optab == len_store_optab)
3188 0 : icode = direct_optab_handler (optab, TYPE_MODE (type));
3189 : else
3190 758 : icode = convert_optab_handler (optab, TYPE_MODE (type),
3191 758 : TYPE_MODE (TREE_TYPE (maskt)));
3192 :
3193 758 : mem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3194 758 : gcc_assert (MEM_P (mem));
3195 : /* The built MEM_REF does not accurately reflect that the store
3196 : is only partial. Clear it. */
3197 758 : set_mem_expr (mem, NULL_TREE);
3198 758 : clear_mem_offset (mem);
3199 758 : reg = expand_normal (rhs);
3200 758 : create_fixed_operand (&ops[i++], mem);
3201 758 : create_input_operand (&ops[i++], reg, TYPE_MODE (type));
3202 758 : i = add_mask_else_and_len_args (ops, i, stmt);
3203 758 : expand_insn (icode, i, ops);
3204 758 : }
3205 :
3206 : #define expand_mask_store_optab_fn expand_partial_store_optab_fn
3207 : #define expand_mask_store_lanes_optab_fn expand_mask_store_optab_fn
3208 : #define expand_len_store_optab_fn expand_partial_store_optab_fn
3209 : #define expand_mask_len_store_optab_fn expand_partial_store_optab_fn
3210 :
3211 : /* Expand VCOND_MASK optab internal function.
3212 : The expansion of STMT happens based on OPTAB table associated. */
3213 :
3214 : static void
3215 8850 : expand_vec_cond_mask_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
3216 : {
3217 8850 : class expand_operand ops[4];
3218 :
3219 8850 : tree lhs = gimple_call_lhs (stmt);
3220 8850 : tree op0 = gimple_call_arg (stmt, 0);
3221 8850 : tree op1 = gimple_call_arg (stmt, 1);
3222 8850 : tree op2 = gimple_call_arg (stmt, 2);
3223 8850 : tree vec_cond_type = TREE_TYPE (lhs);
3224 :
3225 8850 : machine_mode mode = TYPE_MODE (vec_cond_type);
3226 8850 : machine_mode mask_mode = TYPE_MODE (TREE_TYPE (op0));
3227 8850 : enum insn_code icode = convert_optab_handler (optab, mode, mask_mode);
3228 8850 : rtx mask, rtx_op1, rtx_op2;
3229 :
3230 8850 : gcc_assert (icode != CODE_FOR_nothing);
3231 :
3232 8850 : mask = expand_normal (op0);
3233 8850 : rtx_op1 = expand_normal (op1);
3234 8850 : rtx_op2 = expand_normal (op2);
3235 :
3236 8850 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3237 8850 : create_call_lhs_operand (&ops[0], target, mode);
3238 8850 : create_input_operand (&ops[1], rtx_op1, mode);
3239 8850 : create_input_operand (&ops[2], rtx_op2, mode);
3240 8850 : create_input_operand (&ops[3], mask, mask_mode);
3241 8850 : expand_insn (icode, 4, ops);
3242 8850 : assign_call_lhs (lhs, target, &ops[0]);
3243 8850 : }
3244 :
3245 : /* Expand VEC_SET internal functions. */
3246 :
3247 : static void
3248 123 : expand_vec_set_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
3249 : {
3250 123 : tree lhs = gimple_call_lhs (stmt);
3251 123 : tree op0 = gimple_call_arg (stmt, 0);
3252 123 : tree op1 = gimple_call_arg (stmt, 1);
3253 123 : tree op2 = gimple_call_arg (stmt, 2);
3254 123 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3255 123 : rtx src = expand_normal (op0);
3256 :
3257 123 : machine_mode outermode = TYPE_MODE (TREE_TYPE (op0));
3258 123 : scalar_mode innermode = GET_MODE_INNER (outermode);
3259 :
3260 123 : rtx value = expand_normal (op1);
3261 123 : rtx pos = expand_normal (op2);
3262 :
3263 123 : class expand_operand ops[3];
3264 123 : enum insn_code icode = optab_handler (optab, outermode);
3265 :
3266 123 : if (icode != CODE_FOR_nothing)
3267 : {
3268 123 : rtx temp = gen_reg_rtx (outermode);
3269 123 : emit_move_insn (temp, src);
3270 :
3271 123 : create_fixed_operand (&ops[0], temp);
3272 123 : create_input_operand (&ops[1], value, innermode);
3273 123 : create_convert_operand_from (&ops[2], pos, TYPE_MODE (TREE_TYPE (op2)),
3274 : true);
3275 123 : if (maybe_expand_insn (icode, 3, ops))
3276 : {
3277 123 : emit_move_insn (target, temp);
3278 123 : return;
3279 : }
3280 : }
3281 0 : gcc_unreachable ();
3282 : }
3283 :
3284 : static void
3285 1828 : expand_ABNORMAL_DISPATCHER (internal_fn, gcall *)
3286 : {
3287 1828 : }
3288 :
3289 : static void
3290 0 : expand_BUILTIN_EXPECT (internal_fn, gcall *stmt)
3291 : {
3292 : /* When guessing was done, the hints should be already stripped away. */
3293 0 : gcc_assert (!flag_guess_branch_prob || optimize == 0 || seen_error ());
3294 :
3295 0 : rtx target;
3296 0 : tree lhs = gimple_call_lhs (stmt);
3297 0 : if (lhs)
3298 0 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3299 : else
3300 0 : target = const0_rtx;
3301 0 : rtx val = expand_expr (gimple_call_arg (stmt, 0), target, VOIDmode, EXPAND_NORMAL);
3302 0 : if (lhs && val != target)
3303 0 : emit_move_insn (target, val);
3304 0 : }
3305 :
3306 : /* IFN_VA_ARG is supposed to be expanded at pass_stdarg. So this dummy function
3307 : should never be called. */
3308 :
3309 : static void
3310 0 : expand_VA_ARG (internal_fn, gcall *)
3311 : {
3312 0 : gcc_unreachable ();
3313 : }
3314 :
3315 : /* IFN_VEC_CONVERT is supposed to be expanded at pass_lower_vector. So this
3316 : dummy function should never be called. */
3317 :
3318 : static void
3319 0 : expand_VEC_CONVERT (internal_fn, gcall *)
3320 : {
3321 0 : gcc_unreachable ();
3322 : }
3323 :
3324 : /* Expand IFN_RAWMEMCHR internal function. */
3325 :
3326 : void
3327 0 : expand_RAWMEMCHR (internal_fn, gcall *stmt)
3328 : {
3329 0 : expand_operand ops[3];
3330 :
3331 0 : tree lhs = gimple_call_lhs (stmt);
3332 0 : if (!lhs)
3333 0 : return;
3334 0 : machine_mode lhs_mode = TYPE_MODE (TREE_TYPE (lhs));
3335 0 : rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3336 0 : create_call_lhs_operand (&ops[0], lhs_rtx, lhs_mode);
3337 :
3338 0 : tree mem = gimple_call_arg (stmt, 0);
3339 0 : rtx mem_rtx = get_memory_rtx (mem, NULL);
3340 0 : create_fixed_operand (&ops[1], mem_rtx);
3341 :
3342 0 : tree pattern = gimple_call_arg (stmt, 1);
3343 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (pattern));
3344 0 : rtx pattern_rtx = expand_normal (pattern);
3345 0 : create_input_operand (&ops[2], pattern_rtx, mode);
3346 :
3347 0 : insn_code icode = direct_optab_handler (rawmemchr_optab, mode);
3348 :
3349 0 : expand_insn (icode, 3, ops);
3350 0 : assign_call_lhs (lhs, lhs_rtx, &ops[0]);
3351 : }
3352 :
3353 : /* Expand the IFN_UNIQUE function according to its first argument. */
3354 :
3355 : static void
3356 0 : expand_UNIQUE (internal_fn, gcall *stmt)
3357 : {
3358 0 : rtx pattern = NULL_RTX;
3359 0 : enum ifn_unique_kind kind
3360 0 : = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (stmt, 0));
3361 :
3362 0 : switch (kind)
3363 : {
3364 0 : default:
3365 0 : gcc_unreachable ();
3366 :
3367 0 : case IFN_UNIQUE_UNSPEC:
3368 0 : if (targetm.have_unique ())
3369 0 : pattern = targetm.gen_unique ();
3370 : break;
3371 :
3372 0 : case IFN_UNIQUE_OACC_FORK:
3373 0 : case IFN_UNIQUE_OACC_JOIN:
3374 0 : if (targetm.have_oacc_fork () && targetm.have_oacc_join ())
3375 : {
3376 0 : tree lhs = gimple_call_lhs (stmt);
3377 0 : rtx target = const0_rtx;
3378 :
3379 0 : if (lhs)
3380 0 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3381 :
3382 0 : rtx data_dep = expand_normal (gimple_call_arg (stmt, 1));
3383 0 : rtx axis = expand_normal (gimple_call_arg (stmt, 2));
3384 :
3385 0 : if (kind == IFN_UNIQUE_OACC_FORK)
3386 0 : pattern = targetm.gen_oacc_fork (target, data_dep, axis);
3387 : else
3388 0 : pattern = targetm.gen_oacc_join (target, data_dep, axis);
3389 : }
3390 : else
3391 0 : gcc_unreachable ();
3392 : break;
3393 : }
3394 :
3395 0 : if (pattern)
3396 0 : emit_insn (pattern);
3397 0 : }
3398 :
3399 : /* Expand the IFN_DEFERRED_INIT function:
3400 : LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, NAME of the DECL);
3401 :
3402 : Initialize the LHS with zero/pattern according to its second argument
3403 : INIT_TYPE:
3404 : if INIT_TYPE is AUTO_INIT_ZERO, use zeroes to initialize;
3405 : if INIT_TYPE is AUTO_INIT_PATTERN, use 0xFE byte-repeatable pattern
3406 : to initialize;
3407 : The LHS variable is initialized including paddings.
3408 : The reasons to choose 0xFE for pattern initialization are:
3409 : 1. It is a non-canonical virtual address on x86_64, and at the
3410 : high end of the i386 kernel address space.
3411 : 2. It is a very large float value (-1.694739530317379e+38).
3412 : 3. It is also an unusual number for integers. */
3413 : #define INIT_PATTERN_VALUE 0xFE
3414 : static void
3415 29871 : expand_DEFERRED_INIT (internal_fn, gcall *stmt)
3416 : {
3417 29871 : tree lhs = gimple_call_lhs (stmt);
3418 29871 : tree var_size = gimple_call_arg (stmt, 0);
3419 29871 : enum auto_init_type init_type
3420 29871 : = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
3421 29871 : bool reg_lhs = true;
3422 :
3423 29871 : tree var_type = TREE_TYPE (lhs);
3424 29871 : gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
3425 :
3426 29871 : if (TREE_CODE (lhs) == SSA_NAME)
3427 : reg_lhs = true;
3428 : else
3429 : {
3430 : tree lhs_base = lhs;
3431 18744 : while (handled_component_p (lhs_base))
3432 4 : lhs_base = TREE_OPERAND (lhs_base, 0);
3433 18740 : reg_lhs = (mem_ref_refers_to_non_mem_p (lhs_base)
3434 18740 : || non_mem_decl_p (lhs_base));
3435 : /* If this expands to a register and the underlying decl is wrapped in
3436 : a MEM_REF that just serves as an access type change expose the decl
3437 : if it is of correct size. This avoids a situation as in PR103271
3438 : if the target does not support a direct move to the registers mode. */
3439 1665 : if (reg_lhs
3440 1665 : && TREE_CODE (lhs_base) == MEM_REF
3441 4 : && TREE_CODE (TREE_OPERAND (lhs_base, 0)) == ADDR_EXPR
3442 4 : && DECL_P (TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0))
3443 4 : && integer_zerop (TREE_OPERAND (lhs_base, 1))
3444 4 : && tree_fits_uhwi_p (var_size)
3445 4 : && tree_int_cst_equal
3446 4 : (var_size,
3447 4 : DECL_SIZE_UNIT (TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0))))
3448 : {
3449 4 : lhs = TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0);
3450 4 : var_type = TREE_TYPE (lhs);
3451 : }
3452 : }
3453 :
3454 18740 : if (!reg_lhs)
3455 : {
3456 : /* If the variable is not in register, expand to a memset
3457 : to initialize it. */
3458 17075 : mark_addressable (lhs);
3459 17075 : tree var_addr = build_fold_addr_expr (lhs);
3460 :
3461 17075 : tree value = (init_type == AUTO_INIT_PATTERN)
3462 17075 : ? build_int_cst (integer_type_node,
3463 : INIT_PATTERN_VALUE)
3464 16999 : : integer_zero_node;
3465 34150 : tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
3466 : 3, var_addr, value, var_size);
3467 : /* Expand this memset call. */
3468 17075 : expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
3469 : }
3470 : else
3471 : {
3472 : /* If this variable is in a register use expand_assignment.
3473 : For boolean scalars force zero-init. */
3474 12796 : tree init;
3475 12796 : scalar_int_mode var_mode;
3476 12796 : if (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE
3477 12545 : && tree_fits_uhwi_p (var_size)
3478 12545 : && (init_type == AUTO_INIT_PATTERN
3479 12461 : || !is_gimple_reg_type (var_type))
3480 1749 : && int_mode_for_size (tree_to_uhwi (var_size) * BITS_PER_UNIT,
3481 12801 : 0).exists (&var_mode)
3482 14545 : && have_insn_for (SET, var_mode))
3483 : {
3484 1744 : unsigned HOST_WIDE_INT total_bytes = tree_to_uhwi (var_size);
3485 1744 : unsigned char *buf = XALLOCAVEC (unsigned char, total_bytes);
3486 1744 : memset (buf, (init_type == AUTO_INIT_PATTERN
3487 : ? INIT_PATTERN_VALUE : 0), total_bytes);
3488 1744 : tree itype = build_nonstandard_integer_type
3489 1744 : (total_bytes * BITS_PER_UNIT, 1);
3490 1744 : wide_int w = wi::from_buffer (buf, total_bytes);
3491 1744 : init = wide_int_to_tree (itype, w);
3492 : /* Pun the LHS to make sure its type has constant size
3493 : unless it is an SSA name where that's already known. */
3494 1744 : if (TREE_CODE (lhs) != SSA_NAME)
3495 1665 : lhs = build1 (VIEW_CONVERT_EXPR, itype, lhs);
3496 : else
3497 79 : init = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lhs), init);
3498 1744 : }
3499 : else
3500 : /* Use zero-init also for variable-length sizes. */
3501 11052 : init = build_zero_cst (var_type);
3502 :
3503 12796 : expand_assignment (lhs, init, false);
3504 : }
3505 29871 : }
3506 :
3507 : /* Expand the IFN_ACCESS_WITH_SIZE function:
3508 : ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE,
3509 : TYPE_OF_SIZE + ACCESS_MODE, TYPE_SIZE_UNIT for element)
3510 : which returns the REF_TO_OBJ same as the 1st argument;
3511 :
3512 : 1st argument REF_TO_OBJ: The reference to the object;
3513 : 2nd argument REF_TO_SIZE: The reference to the size of the object,
3514 : 3rd argument TYPE_OF_SIZE + ACCESS_MODE: An integer constant with a pointer
3515 : TYPE.
3516 : The pointee TYPE of the pointer TYPE is the TYPE of the object referenced
3517 : by REF_TO_SIZE.
3518 : The integer constant value represents the ACCESS_MODE:
3519 : 0: none
3520 : 1: read_only
3521 : 2: write_only
3522 : 3: read_write
3523 :
3524 : 4th argument: The TYPE_SIZE_UNIT of the element TYPE of the array.
3525 :
3526 : Both the return type and the type of the first argument of this
3527 : function have been converted from the incomplete array type to
3528 : the corresponding pointer type.
3529 :
3530 : For each call to a .ACCESS_WITH_SIZE, replace it with its 1st argument. */
3531 :
3532 : static void
3533 288 : expand_ACCESS_WITH_SIZE (internal_fn, gcall *stmt)
3534 : {
3535 288 : tree lhs = gimple_call_lhs (stmt);
3536 288 : tree ref_to_obj = gimple_call_arg (stmt, 0);
3537 288 : if (lhs)
3538 288 : expand_assignment (lhs, ref_to_obj, false);
3539 288 : }
3540 :
3541 : /* The size of an OpenACC compute dimension. */
3542 :
3543 : static void
3544 5695 : expand_GOACC_DIM_SIZE (internal_fn, gcall *stmt)
3545 : {
3546 5695 : tree lhs = gimple_call_lhs (stmt);
3547 :
3548 5695 : if (!lhs)
3549 : return;
3550 :
3551 5695 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3552 5695 : if (targetm.have_oacc_dim_size ())
3553 : {
3554 0 : rtx dim = expand_expr (gimple_call_arg (stmt, 0), NULL_RTX,
3555 : VOIDmode, EXPAND_NORMAL);
3556 0 : emit_insn (targetm.gen_oacc_dim_size (target, dim));
3557 : }
3558 : else
3559 5695 : emit_move_insn (target, GEN_INT (1));
3560 : }
3561 :
3562 : /* The position of an OpenACC execution engine along one compute axis. */
3563 :
3564 : static void
3565 4567 : expand_GOACC_DIM_POS (internal_fn, gcall *stmt)
3566 : {
3567 4567 : tree lhs = gimple_call_lhs (stmt);
3568 :
3569 4567 : if (!lhs)
3570 : return;
3571 :
3572 4567 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3573 4567 : if (targetm.have_oacc_dim_pos ())
3574 : {
3575 0 : rtx dim = expand_expr (gimple_call_arg (stmt, 0), NULL_RTX,
3576 : VOIDmode, EXPAND_NORMAL);
3577 0 : emit_insn (targetm.gen_oacc_dim_pos (target, dim));
3578 : }
3579 : else
3580 4567 : emit_move_insn (target, const0_rtx);
3581 : }
3582 :
3583 : /* This is expanded by oacc_device_lower pass. */
3584 :
3585 : static void
3586 0 : expand_GOACC_LOOP (internal_fn, gcall *)
3587 : {
3588 0 : gcc_unreachable ();
3589 : }
3590 :
3591 : /* This is expanded by oacc_device_lower pass. */
3592 :
3593 : static void
3594 0 : expand_GOACC_REDUCTION (internal_fn, gcall *)
3595 : {
3596 0 : gcc_unreachable ();
3597 : }
3598 :
3599 : /* This is expanded by oacc_device_lower pass. */
3600 :
3601 : static void
3602 0 : expand_GOACC_TILE (internal_fn, gcall *)
3603 : {
3604 0 : gcc_unreachable ();
3605 : }
3606 :
3607 : /* Set errno to EDOM. */
3608 :
3609 : static void
3610 0 : expand_SET_EDOM (internal_fn, gcall *)
3611 : {
3612 : #ifdef TARGET_EDOM
3613 : #ifdef GEN_ERRNO_RTX
3614 : rtx errno_rtx = GEN_ERRNO_RTX;
3615 : #else
3616 : rtx errno_rtx = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
3617 : #endif
3618 : emit_move_insn (errno_rtx,
3619 : gen_int_mode (TARGET_EDOM, GET_MODE (errno_rtx)));
3620 : #else
3621 0 : gcc_unreachable ();
3622 : #endif
3623 : }
3624 :
3625 : /* Expand atomic bit test and set. */
3626 :
3627 : static void
3628 146 : expand_ATOMIC_BIT_TEST_AND_SET (internal_fn, gcall *call)
3629 : {
3630 146 : expand_ifn_atomic_bit_test_and (call);
3631 146 : }
3632 :
3633 : /* Expand atomic bit test and complement. */
3634 :
3635 : static void
3636 146 : expand_ATOMIC_BIT_TEST_AND_COMPLEMENT (internal_fn, gcall *call)
3637 : {
3638 146 : expand_ifn_atomic_bit_test_and (call);
3639 146 : }
3640 :
3641 : /* Expand atomic bit test and reset. */
3642 :
3643 : static void
3644 135 : expand_ATOMIC_BIT_TEST_AND_RESET (internal_fn, gcall *call)
3645 : {
3646 135 : expand_ifn_atomic_bit_test_and (call);
3647 135 : }
3648 :
3649 : /* Expand atomic bit test and set. */
3650 :
3651 : static void
3652 13870 : expand_ATOMIC_COMPARE_EXCHANGE (internal_fn, gcall *call)
3653 : {
3654 13870 : expand_ifn_atomic_compare_exchange (call);
3655 13870 : }
3656 :
3657 : /* Expand atomic add fetch and cmp with 0. */
3658 :
3659 : static void
3660 885 : expand_ATOMIC_ADD_FETCH_CMP_0 (internal_fn, gcall *call)
3661 : {
3662 885 : expand_ifn_atomic_op_fetch_cmp_0 (call);
3663 885 : }
3664 :
3665 : /* Expand atomic sub fetch and cmp with 0. */
3666 :
3667 : static void
3668 738 : expand_ATOMIC_SUB_FETCH_CMP_0 (internal_fn, gcall *call)
3669 : {
3670 738 : expand_ifn_atomic_op_fetch_cmp_0 (call);
3671 738 : }
3672 :
3673 : /* Expand atomic and fetch and cmp with 0. */
3674 :
3675 : static void
3676 176 : expand_ATOMIC_AND_FETCH_CMP_0 (internal_fn, gcall *call)
3677 : {
3678 176 : expand_ifn_atomic_op_fetch_cmp_0 (call);
3679 176 : }
3680 :
3681 : /* Expand atomic or fetch and cmp with 0. */
3682 :
3683 : static void
3684 112 : expand_ATOMIC_OR_FETCH_CMP_0 (internal_fn, gcall *call)
3685 : {
3686 112 : expand_ifn_atomic_op_fetch_cmp_0 (call);
3687 112 : }
3688 :
3689 : /* Expand atomic xor fetch and cmp with 0. */
3690 :
3691 : static void
3692 176 : expand_ATOMIC_XOR_FETCH_CMP_0 (internal_fn, gcall *call)
3693 : {
3694 176 : expand_ifn_atomic_op_fetch_cmp_0 (call);
3695 176 : }
3696 :
3697 : /* Expand LAUNDER to assignment, lhs = arg0. */
3698 :
3699 : static void
3700 29 : expand_LAUNDER (internal_fn, gcall *call)
3701 : {
3702 29 : tree lhs = gimple_call_lhs (call);
3703 :
3704 29 : if (!lhs)
3705 : return;
3706 :
3707 28 : expand_assignment (lhs, gimple_call_arg (call, 0), false);
3708 : }
3709 :
3710 : /* Expand {MASK_,}SCATTER_STORE{S,U} call CALL using optab OPTAB. */
3711 :
3712 : static void
3713 0 : expand_scatter_store_optab_fn (internal_fn, gcall *stmt, direct_optab optab)
3714 : {
3715 0 : internal_fn ifn = gimple_call_internal_fn (stmt);
3716 0 : int rhs_index = internal_fn_stored_value_index (ifn);
3717 0 : tree base = gimple_call_arg (stmt, 0);
3718 0 : tree offset = gimple_call_arg (stmt, internal_fn_offset_index (ifn));
3719 0 : tree scale = gimple_call_arg (stmt, internal_fn_scale_index (ifn));
3720 0 : tree rhs = gimple_call_arg (stmt, rhs_index);
3721 :
3722 0 : rtx base_rtx = expand_normal (base);
3723 0 : rtx offset_rtx = expand_normal (offset);
3724 0 : HOST_WIDE_INT scale_int = tree_to_shwi (scale);
3725 0 : rtx rhs_rtx = expand_normal (rhs);
3726 :
3727 0 : class expand_operand ops[8];
3728 0 : int i = 0;
3729 0 : create_address_operand (&ops[i++], base_rtx);
3730 0 : create_input_operand (&ops[i++], offset_rtx, TYPE_MODE (TREE_TYPE (offset)));
3731 0 : create_integer_operand (&ops[i++], TYPE_UNSIGNED (TREE_TYPE (offset)));
3732 0 : create_integer_operand (&ops[i++], scale_int);
3733 0 : create_input_operand (&ops[i++], rhs_rtx, TYPE_MODE (TREE_TYPE (rhs)));
3734 0 : i = add_mask_else_and_len_args (ops, i, stmt);
3735 :
3736 0 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (TREE_TYPE (rhs)),
3737 0 : TYPE_MODE (TREE_TYPE (offset)));
3738 0 : expand_insn (icode, i, ops);
3739 0 : }
3740 :
3741 : /* Expand {MASK_,}GATHER_LOAD call CALL using optab OPTAB. */
3742 :
3743 : static void
3744 0 : expand_gather_load_optab_fn (internal_fn ifn, gcall *stmt, direct_optab optab)
3745 : {
3746 0 : tree lhs = gimple_call_lhs (stmt);
3747 0 : tree base = gimple_call_arg (stmt, 0);
3748 0 : tree offset = gimple_call_arg (stmt, internal_fn_offset_index (ifn));
3749 0 : tree scale = gimple_call_arg (stmt, internal_fn_scale_index (ifn));
3750 :
3751 0 : rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3752 0 : rtx base_rtx = expand_normal (base);
3753 0 : rtx offset_rtx = expand_normal (offset);
3754 0 : HOST_WIDE_INT scale_int = tree_to_shwi (scale);
3755 :
3756 0 : int i = 0;
3757 0 : class expand_operand ops[9];
3758 0 : create_call_lhs_operand (&ops[i++], lhs_rtx, TYPE_MODE (TREE_TYPE (lhs)));
3759 0 : create_address_operand (&ops[i++], base_rtx);
3760 0 : create_input_operand (&ops[i++], offset_rtx, TYPE_MODE (TREE_TYPE (offset)));
3761 0 : create_integer_operand (&ops[i++], TYPE_UNSIGNED (TREE_TYPE (offset)));
3762 0 : create_integer_operand (&ops[i++], scale_int);
3763 0 : i = add_mask_else_and_len_args (ops, i, stmt);
3764 0 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)),
3765 0 : TYPE_MODE (TREE_TYPE (offset)));
3766 0 : expand_insn (icode, i, ops);
3767 0 : assign_call_lhs (lhs, lhs_rtx, &ops[0]);
3768 0 : }
3769 :
3770 : /* Expand MASK_LEN_STRIDED_LOAD call CALL by optab OPTAB. */
3771 :
3772 : static void
3773 0 : expand_strided_load_optab_fn (ATTRIBUTE_UNUSED internal_fn, gcall *stmt,
3774 : direct_optab optab)
3775 : {
3776 0 : tree lhs = gimple_call_lhs (stmt);
3777 0 : tree base = gimple_call_arg (stmt, 0);
3778 0 : tree stride = gimple_call_arg (stmt, 1);
3779 :
3780 0 : rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3781 0 : rtx base_rtx = expand_normal (base);
3782 0 : rtx stride_rtx = expand_normal (stride);
3783 :
3784 0 : unsigned i = 0;
3785 0 : class expand_operand ops[7];
3786 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
3787 :
3788 0 : create_output_operand (&ops[i++], lhs_rtx, mode);
3789 0 : create_address_operand (&ops[i++], base_rtx);
3790 0 : create_address_operand (&ops[i++], stride_rtx);
3791 :
3792 0 : i = add_mask_else_and_len_args (ops, i, stmt);
3793 0 : expand_insn (direct_optab_handler (optab, mode), i, ops);
3794 :
3795 0 : if (!rtx_equal_p (lhs_rtx, ops[0].value))
3796 0 : emit_move_insn (lhs_rtx, ops[0].value);
3797 0 : }
3798 :
3799 : /* Expand MASK_LEN_STRIDED_STORE call CALL by optab OPTAB. */
3800 :
3801 : static void
3802 0 : expand_strided_store_optab_fn (ATTRIBUTE_UNUSED internal_fn, gcall *stmt,
3803 : direct_optab optab)
3804 : {
3805 0 : internal_fn fn = gimple_call_internal_fn (stmt);
3806 0 : int rhs_index = internal_fn_stored_value_index (fn);
3807 :
3808 0 : tree base = gimple_call_arg (stmt, 0);
3809 0 : tree stride = gimple_call_arg (stmt, 1);
3810 0 : tree rhs = gimple_call_arg (stmt, rhs_index);
3811 :
3812 0 : rtx base_rtx = expand_normal (base);
3813 0 : rtx stride_rtx = expand_normal (stride);
3814 0 : rtx rhs_rtx = expand_normal (rhs);
3815 :
3816 0 : unsigned i = 0;
3817 0 : class expand_operand ops[6];
3818 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (rhs));
3819 :
3820 0 : create_address_operand (&ops[i++], base_rtx);
3821 0 : create_address_operand (&ops[i++], stride_rtx);
3822 0 : create_input_operand (&ops[i++], rhs_rtx, mode);
3823 :
3824 0 : i = add_mask_else_and_len_args (ops, i, stmt);
3825 0 : expand_insn (direct_optab_handler (optab, mode), i, ops);
3826 0 : }
3827 :
3828 : /* Helper for expand_DIVMOD. Return true if the sequence starting with
3829 : INSN contains any call insns or insns with {,U}{DIV,MOD} rtxes. */
3830 :
3831 : static bool
3832 844 : contains_call_div_mod (rtx_insn *insn)
3833 : {
3834 844 : subrtx_iterator::array_type array;
3835 4849 : for (; insn; insn = NEXT_INSN (insn))
3836 4849 : if (CALL_P (insn))
3837 : return true;
3838 4005 : else if (INSN_P (insn))
3839 17912 : FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST)
3840 13907 : switch (GET_CODE (*iter))
3841 : {
3842 0 : case CALL:
3843 0 : case DIV:
3844 0 : case UDIV:
3845 0 : case MOD:
3846 0 : case UMOD:
3847 0 : return true;
3848 13907 : default:
3849 13907 : break;
3850 : }
3851 : return false;
3852 844 : }
3853 :
3854 : /* Expand DIVMOD() using:
3855 : a) optab handler for udivmod/sdivmod if it is available.
3856 : b) If optab_handler doesn't exist, generate call to
3857 : target-specific divmod libfunc. */
3858 :
3859 : static void
3860 11571 : expand_DIVMOD (internal_fn, gcall *call_stmt)
3861 : {
3862 11571 : tree lhs = gimple_call_lhs (call_stmt);
3863 11571 : tree arg0 = gimple_call_arg (call_stmt, 0);
3864 11571 : tree arg1 = gimple_call_arg (call_stmt, 1);
3865 :
3866 11571 : gcc_assert (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE);
3867 11571 : tree type = TREE_TYPE (TREE_TYPE (lhs));
3868 11571 : machine_mode mode = TYPE_MODE (type);
3869 11571 : bool unsignedp = TYPE_UNSIGNED (type);
3870 11571 : optab tab = (unsignedp) ? udivmod_optab : sdivmod_optab;
3871 :
3872 11571 : rtx op0 = expand_normal (arg0);
3873 11571 : rtx op1 = expand_normal (arg1);
3874 11571 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3875 :
3876 11571 : rtx quotient = NULL_RTX, remainder = NULL_RTX;
3877 11571 : rtx_insn *insns = NULL;
3878 :
3879 11571 : if (TREE_CODE (arg1) == INTEGER_CST)
3880 : {
3881 : /* For DIVMOD by integral constants, there could be efficient code
3882 : expanded inline e.g. using shifts and plus/minus. Try to expand
3883 : the division and modulo and if it emits any library calls or any
3884 : {,U}{DIV,MOD} rtxes throw it away and use a divmod optab or
3885 : divmod libcall. */
3886 1238 : scalar_int_mode int_mode;
3887 1238 : if (remainder == NULL_RTX
3888 1238 : && optimize
3889 1238 : && CONST_INT_P (op1)
3890 1232 : && !pow2p_hwi (INTVAL (op1))
3891 2464 : && is_int_mode (TYPE_MODE (type), &int_mode)
3892 1428 : && GET_MODE_SIZE (int_mode) == 2 * UNITS_PER_WORD
3893 1232 : && optab_handler (and_optab, word_mode) != CODE_FOR_nothing
3894 1232 : && optab_handler (add_optab, word_mode) != CODE_FOR_nothing
3895 1232 : && optimize_insn_for_speed_p ())
3896 : {
3897 1229 : rtx_insn *last = get_last_insn ();
3898 1229 : remainder = NULL_RTX;
3899 3687 : quotient = expand_doubleword_divmod (int_mode, op0, op1, &remainder,
3900 1229 : TYPE_UNSIGNED (type));
3901 1229 : if (quotient != NULL_RTX)
3902 : {
3903 394 : if (optab_handler (mov_optab, int_mode) != CODE_FOR_nothing)
3904 : {
3905 394 : rtx_insn *move = emit_move_insn (quotient, quotient);
3906 788 : set_dst_reg_note (move, REG_EQUAL,
3907 394 : gen_rtx_fmt_ee (TYPE_UNSIGNED (type)
3908 : ? UDIV : DIV, int_mode,
3909 : copy_rtx (op0), op1),
3910 : quotient);
3911 394 : move = emit_move_insn (remainder, remainder);
3912 788 : set_dst_reg_note (move, REG_EQUAL,
3913 394 : gen_rtx_fmt_ee (TYPE_UNSIGNED (type)
3914 : ? UMOD : MOD, int_mode,
3915 : copy_rtx (op0), op1),
3916 : quotient);
3917 : }
3918 : }
3919 : else
3920 835 : delete_insns_since (last);
3921 : }
3922 :
3923 1238 : if (remainder == NULL_RTX)
3924 : {
3925 844 : struct separate_ops ops;
3926 844 : ops.code = TRUNC_DIV_EXPR;
3927 844 : ops.type = type;
3928 844 : ops.op0 = make_tree (ops.type, op0);
3929 844 : ops.op1 = arg1;
3930 844 : ops.op2 = NULL_TREE;
3931 844 : ops.location = gimple_location (call_stmt);
3932 844 : start_sequence ();
3933 844 : quotient = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
3934 844 : if (contains_call_div_mod (get_insns ()))
3935 844 : quotient = NULL_RTX;
3936 : else
3937 : {
3938 0 : ops.code = TRUNC_MOD_EXPR;
3939 0 : remainder = expand_expr_real_2 (&ops, NULL_RTX, mode,
3940 : EXPAND_NORMAL);
3941 0 : if (contains_call_div_mod (get_insns ()))
3942 0 : remainder = NULL_RTX;
3943 : }
3944 844 : if (remainder)
3945 0 : insns = get_insns ();
3946 844 : end_sequence ();
3947 : }
3948 : }
3949 :
3950 11571 : if (remainder)
3951 394 : emit_insn (insns);
3952 :
3953 : /* Check if optab_handler exists for divmod_optab for given mode. */
3954 11177 : else if (optab_handler (tab, mode) != CODE_FOR_nothing)
3955 : {
3956 10280 : quotient = gen_reg_rtx (mode);
3957 10280 : remainder = gen_reg_rtx (mode);
3958 10280 : expand_twoval_binop (tab, op0, op1, quotient, remainder, unsignedp);
3959 : }
3960 :
3961 : /* Generate call to divmod libfunc if it exists. */
3962 897 : else if (rtx libfunc = optab_libfunc (tab, mode))
3963 897 : targetm.expand_divmod_libfunc (libfunc, mode, op0, op1,
3964 : "ient, &remainder);
3965 :
3966 : else
3967 0 : gcc_unreachable ();
3968 :
3969 : /* Wrap the return value (quotient, remainder) within COMPLEX_EXPR. */
3970 23142 : expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
3971 11571 : make_tree (TREE_TYPE (arg0), quotient),
3972 11571 : make_tree (TREE_TYPE (arg1), remainder)),
3973 : target, VOIDmode, EXPAND_NORMAL);
3974 11571 : }
3975 :
3976 : /* Expand a NOP. */
3977 :
3978 : static void
3979 1 : expand_NOP (internal_fn, gcall *)
3980 : {
3981 : /* Nothing. But it shouldn't really prevail. */
3982 1 : }
3983 :
3984 : /* Coroutines, all should have been processed at this stage. */
3985 :
3986 : static void
3987 0 : expand_CO_FRAME (internal_fn, gcall *)
3988 : {
3989 0 : gcc_unreachable ();
3990 : }
3991 :
3992 : static void
3993 0 : expand_CO_YIELD (internal_fn, gcall *)
3994 : {
3995 0 : gcc_unreachable ();
3996 : }
3997 :
3998 : static void
3999 0 : expand_CO_SUSPN (internal_fn, gcall *)
4000 : {
4001 0 : gcc_unreachable ();
4002 : }
4003 :
4004 : static void
4005 0 : expand_CO_ACTOR (internal_fn, gcall *)
4006 : {
4007 0 : gcc_unreachable ();
4008 : }
4009 :
4010 : /* Expand a call to FN using the operands in STMT. FN has a single
4011 : output operand and NARGS input operands. */
4012 :
4013 : static void
4014 79609 : expand_direct_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab,
4015 : unsigned int nargs)
4016 : {
4017 79609 : tree_pair types = direct_internal_fn_types (fn, stmt);
4018 79609 : insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first));
4019 79609 : expand_fn_using_insn (stmt, icode, 1, nargs);
4020 79609 : }
4021 :
4022 : /* Expand WHILE_ULT call STMT using optab OPTAB. */
4023 :
4024 : static void
4025 0 : expand_while_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
4026 : {
4027 0 : expand_operand ops[4];
4028 0 : tree rhs_type[2];
4029 :
4030 0 : tree lhs = gimple_call_lhs (stmt);
4031 0 : tree lhs_type = TREE_TYPE (lhs);
4032 0 : rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
4033 0 : create_call_lhs_operand (&ops[0], lhs_rtx, TYPE_MODE (lhs_type));
4034 :
4035 0 : for (unsigned int i = 0; i < 2; ++i)
4036 : {
4037 0 : tree rhs = gimple_call_arg (stmt, i);
4038 0 : rhs_type[i] = TREE_TYPE (rhs);
4039 0 : rtx rhs_rtx = expand_normal (rhs);
4040 0 : create_input_operand (&ops[i + 1], rhs_rtx, TYPE_MODE (rhs_type[i]));
4041 : }
4042 :
4043 0 : int opcnt;
4044 0 : if (!VECTOR_MODE_P (TYPE_MODE (lhs_type)))
4045 : {
4046 : /* When the mask is an integer mode the exact vector length may not
4047 : be clear to the backend, so we pass it in operand[3].
4048 : Use the vector in arg2 for the most reliable intended size. */
4049 0 : tree type = TREE_TYPE (gimple_call_arg (stmt, 2));
4050 0 : create_integer_operand (&ops[3], TYPE_VECTOR_SUBPARTS (type));
4051 0 : opcnt = 4;
4052 : }
4053 : else
4054 : /* The mask has a vector type so the length operand is unnecessary. */
4055 : opcnt = 3;
4056 :
4057 0 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (rhs_type[0]),
4058 0 : TYPE_MODE (lhs_type));
4059 :
4060 0 : expand_insn (icode, opcnt, ops);
4061 0 : assign_call_lhs (lhs, lhs_rtx, &ops[0]);
4062 0 : }
4063 :
4064 : /* Expand a call to a convert-like optab using the operands in STMT.
4065 : FN has a single output operand and NARGS input operands. */
4066 :
4067 : static void
4068 444 : expand_convert_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab,
4069 : unsigned int nargs)
4070 : {
4071 444 : tree_pair types = direct_internal_fn_types (fn, stmt);
4072 444 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (types.first),
4073 444 : TYPE_MODE (types.second));
4074 444 : expand_fn_using_insn (stmt, icode, 1, nargs);
4075 444 : }
4076 :
4077 : /* Expand CRC call STMT. */
4078 :
4079 : static void
4080 242 : expand_crc_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab)
4081 : {
4082 242 : tree lhs = gimple_call_lhs (stmt);
4083 242 : tree rhs1 = gimple_call_arg (stmt, 0); // crc
4084 242 : tree rhs2 = gimple_call_arg (stmt, 1); // data
4085 242 : tree rhs3 = gimple_call_arg (stmt, 2); // polynomial
4086 :
4087 242 : tree result_type = TREE_TYPE (lhs);
4088 242 : tree data_type = TREE_TYPE (rhs2);
4089 :
4090 242 : gcc_assert (TYPE_MODE (result_type) >= TYPE_MODE (data_type));
4091 :
4092 242 : rtx dest = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
4093 242 : rtx crc = expand_normal (rhs1);
4094 242 : rtx data = expand_normal (rhs2);
4095 242 : rtx polynomial;
4096 242 : if (TREE_CODE (rhs3) != INTEGER_CST)
4097 : {
4098 0 : error ("third argument to %<crc%> builtins must be a constant");
4099 0 : polynomial = const0_rtx;
4100 : }
4101 : else
4102 242 : polynomial = convert_to_mode (TYPE_MODE (result_type), expand_normal (rhs3), 0);
4103 :
4104 : /* Use target specific expansion if it exists.
4105 : Otherwise, generate table-based CRC. */
4106 242 : if (direct_internal_fn_supported_p (fn, tree_pair (data_type, result_type),
4107 : OPTIMIZE_FOR_SPEED))
4108 : {
4109 5 : class expand_operand ops[4];
4110 :
4111 5 : if (dump_file && (dump_flags & TDF_DETAILS))
4112 : {
4113 0 : fprintf (dump_file,
4114 : ";; using optab for crc_%u_polynomial_"
4115 : HOST_WIDE_INT_PRINT_HEX "\n",
4116 0 : GET_MODE_BITSIZE (GET_MODE (dest)).to_constant (),
4117 0 : TREE_INT_CST_LOW (rhs3));
4118 : }
4119 :
4120 5 : create_call_lhs_operand (&ops[0], dest, TYPE_MODE (result_type));
4121 5 : create_input_operand (&ops[1], crc, TYPE_MODE (result_type));
4122 5 : create_input_operand (&ops[2], data, TYPE_MODE (data_type));
4123 5 : create_input_operand (&ops[3], polynomial, TYPE_MODE (result_type));
4124 5 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (data_type),
4125 5 : TYPE_MODE (result_type));
4126 5 : expand_insn (icode, 4, ops);
4127 5 : assign_call_lhs (lhs, dest, &ops[0]);
4128 : }
4129 : else
4130 : {
4131 : /* We're bypassing all the operand conversions that are done in the
4132 : case when we get an icode, operands and pass that off to expand_insn.
4133 :
4134 : That path has special case handling for promoted return values which
4135 : we must emulate here (is the same kind of special treatment ever
4136 : needed for input arguments here?).
4137 :
4138 : In particular we do not want to store directly into a promoted
4139 : SUBREG destination, instead store into a suitably sized pseudo. */
4140 237 : rtx orig_dest = dest;
4141 237 : if (SUBREG_P (dest) && SUBREG_PROMOTED_VAR_P (dest))
4142 0 : dest = gen_reg_rtx (GET_MODE (dest));
4143 :
4144 : /* If it's IFN_CRC generate bit-forward CRC. */
4145 237 : if (fn == IFN_CRC)
4146 117 : expand_crc_table_based (dest, crc, data, polynomial,
4147 117 : TYPE_MODE (data_type));
4148 : else
4149 : /* If it's IFN_CRC_REV generate bit-reversed CRC. */
4150 120 : expand_reversed_crc_table_based (dest, crc, data, polynomial,
4151 120 : TYPE_MODE (data_type),
4152 : generate_reflecting_code_standard);
4153 :
4154 : /* Now get the return value where it needs to be, taking care to
4155 : ensure it's promoted appropriately if the ABI demands it.
4156 :
4157 : Re-use assign_call_lhs to handle the details. */
4158 237 : class expand_operand ops[4];
4159 237 : create_call_lhs_operand (&ops[0], dest, TYPE_MODE (result_type));
4160 237 : ops[0].value = dest;
4161 237 : assign_call_lhs (lhs, orig_dest, &ops[0]);
4162 : }
4163 242 : }
4164 :
4165 : /* Expand .REDUC_SBOOL_{AND,IOR,XOR}. */
4166 :
4167 : static void
4168 33 : expand_reduc_sbool_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab)
4169 : {
4170 33 : tree_pair types = direct_internal_fn_types (fn, stmt);
4171 33 : insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first));
4172 :
4173 : /* Below copied from expand_fn_using_insn. */
4174 :
4175 33 : gcc_assert (icode != CODE_FOR_nothing);
4176 :
4177 33 : expand_operand *ops = XALLOCAVEC (expand_operand, 3);
4178 33 : rtx lhs_rtx = NULL_RTX;
4179 33 : tree lhs = gimple_call_lhs (stmt);
4180 33 : if (lhs)
4181 33 : lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
4182 33 : create_call_lhs_operand (&ops[0], lhs_rtx,
4183 33 : insn_data[icode].operand[0].mode);
4184 :
4185 33 : tree rhs = gimple_call_arg (stmt, 0);
4186 33 : tree rhs_type = TREE_TYPE (rhs);
4187 33 : rtx rhs_rtx = expand_normal (rhs);
4188 33 : gcc_assert (VECTOR_BOOLEAN_TYPE_P (rhs_type));
4189 33 : create_input_operand (&ops[1], rhs_rtx, TYPE_MODE (rhs_type));
4190 33 : if (SCALAR_INT_MODE_P (TYPE_MODE (rhs_type)))
4191 : {
4192 18 : rtx nunits = GEN_INT (TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ());
4193 18 : gcc_assert (insn_operand_matches (icode, 2, nunits));
4194 18 : create_input_operand (&ops[2], nunits, SImode);
4195 : }
4196 51 : expand_insn (icode, SCALAR_INT_MODE_P (TYPE_MODE (rhs_type)) ? 3 : 2, ops);
4197 33 : if (lhs_rtx)
4198 33 : assign_call_lhs (lhs, lhs_rtx, &ops[0]);
4199 33 : }
4200 :
4201 : /* Expanders for optabs that can use expand_direct_optab_fn. */
4202 :
4203 : #define expand_unary_optab_fn(FN, STMT, OPTAB) \
4204 : expand_direct_optab_fn (FN, STMT, OPTAB, 1)
4205 :
4206 : #define expand_binary_optab_fn(FN, STMT, OPTAB) \
4207 : expand_direct_optab_fn (FN, STMT, OPTAB, 2)
4208 :
4209 : #define expand_ternary_optab_fn(FN, STMT, OPTAB) \
4210 : expand_direct_optab_fn (FN, STMT, OPTAB, 3)
4211 :
4212 : #define expand_cond_unary_optab_fn(FN, STMT, OPTAB) \
4213 : expand_direct_optab_fn (FN, STMT, OPTAB, 3)
4214 :
4215 : #define expand_cond_binary_optab_fn(FN, STMT, OPTAB) \
4216 : expand_direct_optab_fn (FN, STMT, OPTAB, 4)
4217 :
4218 : #define expand_cond_ternary_optab_fn(FN, STMT, OPTAB) \
4219 : expand_direct_optab_fn (FN, STMT, OPTAB, 5)
4220 :
4221 : #define expand_cond_len_unary_optab_fn(FN, STMT, OPTAB) \
4222 : expand_direct_optab_fn (FN, STMT, OPTAB, 5)
4223 :
4224 : #define expand_cond_len_binary_optab_fn(FN, STMT, OPTAB) \
4225 : expand_direct_optab_fn (FN, STMT, OPTAB, 6)
4226 :
4227 : #define expand_cond_len_ternary_optab_fn(FN, STMT, OPTAB) \
4228 : expand_direct_optab_fn (FN, STMT, OPTAB, 7)
4229 :
4230 : #define expand_fold_extract_optab_fn(FN, STMT, OPTAB) \
4231 : expand_direct_optab_fn (FN, STMT, OPTAB, 3)
4232 :
4233 : #define expand_fold_len_extract_optab_fn(FN, STMT, OPTAB) \
4234 : expand_direct_optab_fn (FN, STMT, OPTAB, 5)
4235 :
4236 : #define expand_fold_left_optab_fn(FN, STMT, OPTAB) \
4237 : expand_direct_optab_fn (FN, STMT, OPTAB, 2)
4238 :
4239 : #define expand_mask_fold_left_optab_fn(FN, STMT, OPTAB) \
4240 : expand_direct_optab_fn (FN, STMT, OPTAB, 3)
4241 :
4242 : #define expand_mask_len_fold_left_optab_fn(FN, STMT, OPTAB) \
4243 : expand_direct_optab_fn (FN, STMT, OPTAB, 5)
4244 :
4245 : #define expand_check_ptrs_optab_fn(FN, STMT, OPTAB) \
4246 : expand_direct_optab_fn (FN, STMT, OPTAB, 4)
4247 :
4248 : #define expand_select_vl_optab_fn(FN, STMT, OPTAB) \
4249 : expand_convert_optab_fn (FN, STMT, OPTAB, 3)
4250 :
4251 : /* Expanders for optabs that can use expand_convert_optab_fn. */
4252 :
4253 : #define expand_unary_convert_optab_fn(FN, STMT, OPTAB) \
4254 : expand_convert_optab_fn (FN, STMT, OPTAB, 1)
4255 :
4256 : #define expand_vec_extract_optab_fn(FN, STMT, OPTAB) \
4257 : expand_convert_optab_fn (FN, STMT, OPTAB, 2)
4258 :
4259 : /* RETURN_TYPE and ARGS are a return type and argument list that are
4260 : in principle compatible with FN (which satisfies direct_internal_fn_p).
4261 : Return the types that should be used to determine whether the
4262 : target supports FN. */
4263 :
4264 : tree_pair
4265 8202 : direct_internal_fn_types (internal_fn fn, tree return_type, tree *args)
4266 : {
4267 8202 : const direct_internal_fn_info &info = direct_internal_fn (fn);
4268 8202 : tree type0 = (info.type0 < 0 ? return_type : TREE_TYPE (args[info.type0]));
4269 8202 : tree type1 = (info.type1 < 0 ? return_type : TREE_TYPE (args[info.type1]));
4270 8202 : return tree_pair (type0, type1);
4271 : }
4272 :
4273 : /* CALL is a call whose return type and arguments are in principle
4274 : compatible with FN (which satisfies direct_internal_fn_p). Return the
4275 : types that should be used to determine whether the target supports FN. */
4276 :
4277 : tree_pair
4278 140813 : direct_internal_fn_types (internal_fn fn, gcall *call)
4279 : {
4280 140813 : const direct_internal_fn_info &info = direct_internal_fn (fn);
4281 140813 : tree op0 = (info.type0 < 0
4282 140813 : ? gimple_call_lhs (call)
4283 139337 : : gimple_call_arg (call, info.type0));
4284 140813 : tree op1 = (info.type1 < 0
4285 140813 : ? gimple_call_lhs (call)
4286 140772 : : gimple_call_arg (call, info.type1));
4287 140813 : return tree_pair (TREE_TYPE (op0), TREE_TYPE (op1));
4288 : }
4289 :
4290 : /* Return true if OPTAB is supported for TYPES (whose modes should be
4291 : the same) when the optimization type is OPT_TYPE. Used for simple
4292 : direct optabs. */
4293 :
4294 : static bool
4295 4015485 : direct_optab_supported_p (direct_optab optab, tree_pair types,
4296 : optimization_type opt_type)
4297 : {
4298 4015485 : machine_mode mode = TYPE_MODE (types.first);
4299 4015485 : gcc_checking_assert (mode == TYPE_MODE (types.second));
4300 4015485 : return direct_optab_handler (optab, mode, opt_type) != CODE_FOR_nothing;
4301 : }
4302 :
4303 : /* Return true if OPTAB is supported for TYPES, where the first type
4304 : is the destination and the second type is the source. Used for
4305 : convert optabs. */
4306 :
4307 : static bool
4308 80557 : convert_optab_supported_p (convert_optab optab, tree_pair types,
4309 : optimization_type opt_type)
4310 : {
4311 80557 : return (convert_optab_handler (optab, TYPE_MODE (types.first),
4312 80557 : TYPE_MODE (types.second), opt_type)
4313 80557 : != CODE_FOR_nothing);
4314 : }
4315 :
4316 : /* Return true if load/store lanes optab OPTAB is supported for
4317 : array type TYPES.first when the optimization type is OPT_TYPE. */
4318 :
4319 : static bool
4320 0 : multi_vector_optab_supported_p (convert_optab optab, tree_pair types,
4321 : optimization_type opt_type)
4322 : {
4323 0 : gcc_assert (TREE_CODE (types.first) == ARRAY_TYPE);
4324 0 : machine_mode imode = TYPE_MODE (types.first);
4325 0 : machine_mode vmode = TYPE_MODE (TREE_TYPE (types.first));
4326 0 : return (convert_optab_handler (optab, imode, vmode, opt_type)
4327 0 : != CODE_FOR_nothing);
4328 : }
4329 :
4330 : #define direct_unary_optab_supported_p direct_optab_supported_p
4331 : #define direct_unary_convert_optab_supported_p convert_optab_supported_p
4332 : #define direct_binary_optab_supported_p direct_optab_supported_p
4333 : #define direct_ternary_optab_supported_p direct_optab_supported_p
4334 : #define direct_cond_unary_optab_supported_p direct_optab_supported_p
4335 : #define direct_cond_binary_optab_supported_p direct_optab_supported_p
4336 : #define direct_cond_ternary_optab_supported_p direct_optab_supported_p
4337 : #define direct_cond_len_unary_optab_supported_p direct_optab_supported_p
4338 : #define direct_cond_len_binary_optab_supported_p direct_optab_supported_p
4339 : #define direct_cond_len_ternary_optab_supported_p direct_optab_supported_p
4340 : #define direct_crc_optab_supported_p convert_optab_supported_p
4341 : #define direct_mask_load_optab_supported_p convert_optab_supported_p
4342 : #define direct_load_lanes_optab_supported_p multi_vector_optab_supported_p
4343 : #define direct_mask_load_lanes_optab_supported_p multi_vector_optab_supported_p
4344 : #define direct_gather_load_optab_supported_p convert_optab_supported_p
4345 : #define direct_strided_load_optab_supported_p direct_optab_supported_p
4346 : #define direct_len_load_optab_supported_p direct_optab_supported_p
4347 : #define direct_mask_len_load_optab_supported_p convert_optab_supported_p
4348 : #define direct_mask_store_optab_supported_p convert_optab_supported_p
4349 : #define direct_store_lanes_optab_supported_p multi_vector_optab_supported_p
4350 : #define direct_mask_store_lanes_optab_supported_p multi_vector_optab_supported_p
4351 : #define direct_vec_cond_mask_optab_supported_p convert_optab_supported_p
4352 : #define direct_vec_cond_optab_supported_p convert_optab_supported_p
4353 : #define direct_scatter_store_optab_supported_p convert_optab_supported_p
4354 : #define direct_strided_store_optab_supported_p direct_optab_supported_p
4355 : #define direct_len_store_optab_supported_p direct_optab_supported_p
4356 : #define direct_mask_len_store_optab_supported_p convert_optab_supported_p
4357 : #define direct_while_optab_supported_p convert_optab_supported_p
4358 : #define direct_fold_extract_optab_supported_p direct_optab_supported_p
4359 : #define direct_fold_len_extract_optab_supported_p direct_optab_supported_p
4360 : #define direct_fold_left_optab_supported_p direct_optab_supported_p
4361 : #define direct_mask_fold_left_optab_supported_p direct_optab_supported_p
4362 : #define direct_mask_len_fold_left_optab_supported_p direct_optab_supported_p
4363 : #define direct_check_ptrs_optab_supported_p direct_optab_supported_p
4364 : #define direct_vec_set_optab_supported_p direct_optab_supported_p
4365 : #define direct_vec_extract_optab_supported_p convert_optab_supported_p
4366 : #define direct_reduc_sbool_optab_supported_p direct_optab_supported_p
4367 : #define direct_select_vl_optab_supported_p convert_optab_supported_p
4368 :
4369 : /* Return the optab used by internal function FN. */
4370 :
4371 : optab
4372 210481 : direct_internal_fn_optab (internal_fn fn, tree_pair types)
4373 : {
4374 210481 : switch (fn)
4375 : {
4376 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
4377 : case IFN_##CODE: break;
4378 : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
4379 : case IFN_##CODE: return OPTAB##_optab;
4380 : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
4381 : UNSIGNED_OPTAB, TYPE) \
4382 : case IFN_##CODE: return (TYPE_UNSIGNED (types.SELECTOR) \
4383 : ? UNSIGNED_OPTAB ## _optab \
4384 : : SIGNED_OPTAB ## _optab);
4385 : #include "internal-fn.def"
4386 :
4387 : case IFN_LAST:
4388 : break;
4389 : }
4390 0 : gcc_unreachable ();
4391 : }
4392 :
4393 : /* Return the optab used by internal function FN. */
4394 :
4395 : static optab
4396 1149076 : direct_internal_fn_optab (internal_fn fn)
4397 : {
4398 1149076 : switch (fn)
4399 : {
4400 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
4401 : case IFN_##CODE: break;
4402 : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
4403 : case IFN_##CODE: return OPTAB##_optab;
4404 : #include "internal-fn.def"
4405 :
4406 : case IFN_LAST:
4407 : break;
4408 : }
4409 0 : gcc_unreachable ();
4410 : }
4411 :
4412 : /* Return true if TYPE's mode has the same format as TYPE, and if there is
4413 : a 1:1 correspondence between the values that the mode can store and the
4414 : values that the type can store. */
4415 :
4416 : static bool
4417 8322272 : type_strictly_matches_mode_p (const_tree type)
4418 : {
4419 : /* The masked vector operations have both vector data operands and vector
4420 : boolean operands. The vector data operands are expected to have a vector
4421 : mode, but the vector boolean operands can be an integer mode rather than
4422 : a vector mode, depending on how TARGET_VECTORIZE_GET_MASK_MODE is
4423 : defined. PR116103. */
4424 1081266 : if (VECTOR_BOOLEAN_TYPE_P (type)
4425 277320 : && SCALAR_INT_MODE_P (TYPE_MODE (type))
4426 8391218 : && TYPE_PRECISION (TREE_TYPE (type)) == 1)
4427 : return true;
4428 :
4429 8253327 : if (VECTOR_TYPE_P (type))
4430 1012321 : return VECTOR_MODE_P (TYPE_MODE (type));
4431 :
4432 7241006 : if (INTEGRAL_TYPE_P (type))
4433 6836630 : return type_has_mode_precision_p (type);
4434 :
4435 404376 : if (SCALAR_FLOAT_TYPE_P (type) || COMPLEX_FLOAT_TYPE_P (type))
4436 : return true;
4437 :
4438 : return false;
4439 : }
4440 :
4441 : /* Returns true if both types of TYPE_PAIR strictly match their modes,
4442 : else returns false. */
4443 :
4444 : static bool
4445 4226230 : type_pair_strictly_matches_mode_p (tree_pair type_pair)
4446 : {
4447 4226230 : return type_strictly_matches_mode_p (type_pair.first)
4448 4226230 : && type_strictly_matches_mode_p (type_pair.second);
4449 : }
4450 :
4451 : /* Return true if FN is supported for the types in TYPES when the
4452 : optimization type is OPT_TYPE. The types are those associated with
4453 : the "type0" and "type1" fields of FN's direct_internal_fn_info
4454 : structure. */
4455 :
4456 : bool
4457 4226230 : direct_internal_fn_supported_p (internal_fn fn, tree_pair types,
4458 : optimization_type opt_type)
4459 : {
4460 4226230 : if (!type_pair_strictly_matches_mode_p (types))
4461 : return false;
4462 :
4463 4096042 : switch (fn)
4464 : {
4465 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
4466 : case IFN_##CODE: break;
4467 : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
4468 : case IFN_##CODE: \
4469 : return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types, \
4470 : opt_type);
4471 : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
4472 : UNSIGNED_OPTAB, TYPE) \
4473 : case IFN_##CODE: \
4474 : { \
4475 : optab which_optab = (TYPE_UNSIGNED (types.SELECTOR) \
4476 : ? UNSIGNED_OPTAB ## _optab \
4477 : : SIGNED_OPTAB ## _optab); \
4478 : return direct_##TYPE##_optab_supported_p (which_optab, types, \
4479 : opt_type); \
4480 : }
4481 : #include "internal-fn.def"
4482 :
4483 : case IFN_LAST:
4484 : break;
4485 : }
4486 0 : gcc_unreachable ();
4487 : }
4488 :
4489 : /* Return true if FN is supported for type TYPE when the optimization
4490 : type is OPT_TYPE. The caller knows that the "type0" and "type1"
4491 : fields of FN's direct_internal_fn_info structure are the same. */
4492 :
4493 : bool
4494 4070365 : direct_internal_fn_supported_p (internal_fn fn, tree type,
4495 : optimization_type opt_type)
4496 : {
4497 4070365 : const direct_internal_fn_info &info = direct_internal_fn (fn);
4498 4070365 : gcc_checking_assert (info.type0 == info.type1);
4499 4070365 : return direct_internal_fn_supported_p (fn, tree_pair (type, type), opt_type);
4500 : }
4501 :
4502 : /* Return true if the STMT is supported when the optimization type is OPT_TYPE,
4503 : given that STMT is a call to a direct internal function. */
4504 :
4505 : bool
4506 384 : direct_internal_fn_supported_p (gcall *stmt, optimization_type opt_type)
4507 : {
4508 384 : internal_fn fn = gimple_call_internal_fn (stmt);
4509 384 : tree_pair types = direct_internal_fn_types (fn, stmt);
4510 384 : return direct_internal_fn_supported_p (fn, types, opt_type);
4511 : }
4512 :
4513 : /* Return true if FN is a binary operation and if FN is commutative. */
4514 :
4515 : bool
4516 32786149 : commutative_binary_fn_p (internal_fn fn)
4517 : {
4518 32786149 : switch (fn)
4519 : {
4520 : case IFN_AVG_FLOOR:
4521 : case IFN_AVG_CEIL:
4522 : case IFN_MULH:
4523 : case IFN_MULHS:
4524 : case IFN_MULHRS:
4525 : case IFN_FMIN:
4526 : case IFN_FMAX:
4527 : case IFN_COMPLEX_MUL:
4528 : case IFN_UBSAN_CHECK_ADD:
4529 : case IFN_UBSAN_CHECK_MUL:
4530 : case IFN_ADD_OVERFLOW:
4531 : case IFN_MUL_OVERFLOW:
4532 : case IFN_SAT_ADD:
4533 : case IFN_SAT_MUL:
4534 : case IFN_VEC_WIDEN_PLUS:
4535 : case IFN_VEC_WIDEN_PLUS_LO:
4536 : case IFN_VEC_WIDEN_PLUS_HI:
4537 : case IFN_VEC_WIDEN_PLUS_EVEN:
4538 : case IFN_VEC_WIDEN_PLUS_ODD:
4539 : return true;
4540 :
4541 31894442 : default:
4542 31894442 : return false;
4543 : }
4544 : }
4545 :
4546 : /* Return true if FN is a ternary operation and if its first two arguments
4547 : are commutative. */
4548 :
4549 : bool
4550 26598039 : commutative_ternary_fn_p (internal_fn fn)
4551 : {
4552 26598039 : switch (fn)
4553 : {
4554 : case IFN_FMA:
4555 : case IFN_FMS:
4556 : case IFN_FNMA:
4557 : case IFN_FNMS:
4558 : case IFN_UADDC:
4559 : return true;
4560 :
4561 26469961 : default:
4562 26469961 : return false;
4563 : }
4564 : }
4565 :
4566 : /* Return true if FN is an associative binary operation. */
4567 :
4568 : bool
4569 52 : associative_binary_fn_p (internal_fn fn)
4570 : {
4571 52 : switch (fn)
4572 : {
4573 : case IFN_FMIN:
4574 : case IFN_FMAX:
4575 : return true;
4576 :
4577 0 : default:
4578 0 : return false;
4579 : }
4580 : }
4581 :
4582 : /* If FN is commutative in two consecutive arguments, return the
4583 : index of the first, otherwise return -1. */
4584 :
4585 : int
4586 26924676 : first_commutative_argument (internal_fn fn)
4587 : {
4588 26924676 : switch (fn)
4589 : {
4590 : case IFN_COND_ADD:
4591 : case IFN_COND_MUL:
4592 : case IFN_COND_MIN:
4593 : case IFN_COND_MAX:
4594 : case IFN_COND_FMIN:
4595 : case IFN_COND_FMAX:
4596 : case IFN_COND_AND:
4597 : case IFN_COND_IOR:
4598 : case IFN_COND_XOR:
4599 : case IFN_COND_FMA:
4600 : case IFN_COND_FMS:
4601 : case IFN_COND_FNMA:
4602 : case IFN_COND_FNMS:
4603 : case IFN_COND_LEN_ADD:
4604 : case IFN_COND_LEN_MUL:
4605 : case IFN_COND_LEN_MIN:
4606 : case IFN_COND_LEN_MAX:
4607 : case IFN_COND_LEN_FMIN:
4608 : case IFN_COND_LEN_FMAX:
4609 : case IFN_COND_LEN_AND:
4610 : case IFN_COND_LEN_IOR:
4611 : case IFN_COND_LEN_XOR:
4612 : case IFN_COND_LEN_FMA:
4613 : case IFN_COND_LEN_FMS:
4614 : case IFN_COND_LEN_FNMA:
4615 : case IFN_COND_LEN_FNMS:
4616 : return 1;
4617 :
4618 26906222 : default:
4619 26906222 : if (commutative_binary_fn_p (fn)
4620 26906222 : || commutative_ternary_fn_p (fn))
4621 436285 : return 0;
4622 : return -1;
4623 : }
4624 : }
4625 :
4626 : /* Return true if this CODE describes an internal_fn that returns a vector with
4627 : elements twice as wide as the element size of the input vectors. */
4628 :
4629 : bool
4630 1786723 : widening_fn_p (code_helper code)
4631 : {
4632 1786723 : if (!code.is_fn_code ())
4633 : return false;
4634 :
4635 161553 : if (!internal_fn_p ((combined_fn) code))
4636 : return false;
4637 :
4638 161553 : internal_fn fn = as_internal_fn ((combined_fn) code);
4639 161553 : switch (fn)
4640 : {
4641 : #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T) \
4642 : case IFN_##NAME: \
4643 : case IFN_##NAME##_HI: \
4644 : case IFN_##NAME##_LO: \
4645 : case IFN_##NAME##_EVEN: \
4646 : case IFN_##NAME##_ODD: \
4647 : return true;
4648 : #include "internal-fn.def"
4649 :
4650 : default:
4651 : return false;
4652 : }
4653 : }
4654 :
4655 : /* Return true if this CODE describes an internal_fn that returns a vector with
4656 : elements twice as wide as the element size of the input vectors and operates
4657 : on even/odd parts of the input. */
4658 :
4659 : bool
4660 17144 : widening_evenodd_fn_p (code_helper code)
4661 : {
4662 17144 : if (!code.is_fn_code ())
4663 : return false;
4664 :
4665 0 : if (!internal_fn_p ((combined_fn) code))
4666 : return false;
4667 :
4668 0 : internal_fn fn = as_internal_fn ((combined_fn) code);
4669 0 : switch (fn)
4670 : {
4671 : #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T) \
4672 : case IFN_##NAME##_EVEN: \
4673 : case IFN_##NAME##_ODD: \
4674 : return true;
4675 : #include "internal-fn.def"
4676 :
4677 : default:
4678 : return false;
4679 : }
4680 : }
4681 :
4682 : /* Return true if IFN_SET_EDOM is supported. */
4683 :
4684 : bool
4685 139 : set_edom_supported_p (void)
4686 : {
4687 : #ifdef TARGET_EDOM
4688 : return true;
4689 : #else
4690 139 : return false;
4691 : #endif
4692 : }
4693 :
4694 : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
4695 : static void \
4696 : expand_##CODE (internal_fn fn, gcall *stmt) \
4697 : { \
4698 : expand_##TYPE##_optab_fn (fn, stmt, OPTAB##_optab); \
4699 : }
4700 : #define DEF_INTERNAL_INT_EXT_FN(CODE, FLAGS, OPTAB, TYPE)
4701 : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
4702 : UNSIGNED_OPTAB, TYPE) \
4703 : static void \
4704 : expand_##CODE (internal_fn fn, gcall *stmt) \
4705 : { \
4706 : tree_pair types = direct_internal_fn_types (fn, stmt); \
4707 : optab which_optab = direct_internal_fn_optab (fn, types); \
4708 : expand_##TYPE##_optab_fn (fn, stmt, which_optab); \
4709 : }
4710 : #include "internal-fn.def"
4711 :
4712 : /* Routines to expand each internal function, indexed by function number.
4713 : Each routine has the prototype:
4714 :
4715 : expand_<NAME> (gcall *stmt)
4716 :
4717 : where STMT is the statement that performs the call. */
4718 : static void (*const internal_fn_expanders[]) (internal_fn, gcall *) = {
4719 :
4720 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) expand_##CODE,
4721 : #include "internal-fn.def"
4722 : 0
4723 : };
4724 :
4725 : /* Invoke T(CODE, SUFFIX) for each conditional function IFN_COND_##SUFFIX
4726 : that maps to a tree code CODE. There is also an IFN_COND_LEN_##SUFFIX
4727 : for each such IFN_COND_##SUFFIX. */
4728 : #define FOR_EACH_CODE_MAPPING(T) \
4729 : T (PLUS_EXPR, ADD) \
4730 : T (MINUS_EXPR, SUB) \
4731 : T (MULT_EXPR, MUL) \
4732 : T (TRUNC_DIV_EXPR, DIV) \
4733 : T (TRUNC_MOD_EXPR, MOD) \
4734 : T (RDIV_EXPR, RDIV) \
4735 : T (MIN_EXPR, MIN) \
4736 : T (MAX_EXPR, MAX) \
4737 : T (BIT_AND_EXPR, AND) \
4738 : T (BIT_IOR_EXPR, IOR) \
4739 : T (BIT_XOR_EXPR, XOR) \
4740 : T (LSHIFT_EXPR, SHL) \
4741 : T (RSHIFT_EXPR, SHR) \
4742 : T (NEGATE_EXPR, NEG)
4743 :
4744 : /* Return a function that only performs CODE when a certain condition is met
4745 : and that uses a given fallback value otherwise. For example, if CODE is
4746 : a binary operation associated with conditional function FN:
4747 :
4748 : LHS = FN (COND, A, B, ELSE)
4749 :
4750 : is equivalent to the C expression:
4751 :
4752 : LHS = COND ? A CODE B : ELSE;
4753 :
4754 : operating elementwise if the operands are vectors.
4755 :
4756 : Return IFN_LAST if no such function exists. */
4757 :
4758 : internal_fn
4759 556802 : get_conditional_internal_fn (tree_code code)
4760 : {
4761 556802 : switch (code)
4762 : {
4763 : #define CASE(CODE, IFN) case CODE: return IFN_COND_##IFN;
4764 : FOR_EACH_CODE_MAPPING(CASE)
4765 : #undef CASE
4766 : default:
4767 : return IFN_LAST;
4768 : }
4769 : }
4770 :
4771 : /* If IFN implements the conditional form of a tree code, return that
4772 : tree code, otherwise return ERROR_MARK. */
4773 :
4774 : tree_code
4775 3188308 : conditional_internal_fn_code (internal_fn ifn)
4776 : {
4777 3188308 : switch (ifn)
4778 : {
4779 : #define CASE(CODE, IFN) \
4780 : case IFN_COND_##IFN: \
4781 : case IFN_COND_LEN_##IFN: \
4782 : return CODE;
4783 : FOR_EACH_CODE_MAPPING (CASE)
4784 : #undef CASE
4785 : default:
4786 : return ERROR_MARK;
4787 : }
4788 : }
4789 :
4790 : /* Like get_conditional_internal_fn, but return a function that
4791 : additionally restricts the operation to the leading elements
4792 : of a vector. The number of elements to process is given by a length
4793 : and bias pair, as for IFN_LOAD_LEN. The values of the remaining
4794 : elements are taken from the fallback ("else") argument.
4795 :
4796 : For example, if CODE is a binary operation associated with FN:
4797 :
4798 : LHS = FN (COND, A, B, ELSE, LEN, BIAS)
4799 :
4800 : is equivalent to the C code:
4801 :
4802 : for (int i = 0; i < NUNITS; i++)
4803 : {
4804 : if (i < LEN + BIAS && COND[i])
4805 : LHS[i] = A[i] CODE B[i];
4806 : else
4807 : LHS[i] = ELSE[i];
4808 : }
4809 : */
4810 :
4811 : internal_fn
4812 534241 : get_conditional_len_internal_fn (tree_code code)
4813 : {
4814 534241 : switch (code)
4815 : {
4816 : #define CASE(CODE, IFN) case CODE: return IFN_COND_LEN_##IFN;
4817 : FOR_EACH_CODE_MAPPING(CASE)
4818 : #undef CASE
4819 : default:
4820 : return IFN_LAST;
4821 : }
4822 : }
4823 :
4824 : /* Invoke T(IFN) for each internal function IFN that also has an
4825 : IFN_COND_* form. */
4826 : #define FOR_EACH_COND_FN_PAIR(T) \
4827 : T (FMAX) \
4828 : T (FMIN) \
4829 : T (FMA) \
4830 : T (FMS) \
4831 : T (FNMA) \
4832 : T (FNMS) \
4833 : T (SQRT) \
4834 : T (ROUND) \
4835 : T (FLOOR) \
4836 : T (RINT) \
4837 : T (CEIL)
4838 :
4839 : /* Return a function that only performs internal function FN when a
4840 : certain condition is met and that uses a given fallback value otherwise.
4841 : In other words, the returned function FN' is such that:
4842 :
4843 : LHS = FN' (COND, A1, ... An, ELSE)
4844 :
4845 : is equivalent to the C expression:
4846 :
4847 : LHS = COND ? FN (A1, ..., An) : ELSE;
4848 :
4849 : operating elementwise if the operands are vectors.
4850 :
4851 : Return IFN_LAST if no such function exists. */
4852 :
4853 : internal_fn
4854 8488 : get_conditional_internal_fn (internal_fn fn)
4855 : {
4856 8488 : switch (fn)
4857 : {
4858 : #define CASE(NAME) case IFN_##NAME: return IFN_COND_##NAME;
4859 1850 : FOR_EACH_COND_FN_PAIR(CASE)
4860 : #undef CASE
4861 6637 : default:
4862 6637 : return IFN_LAST;
4863 : }
4864 : }
4865 :
4866 : /* If there exists an internal function like IFN that operates on vectors,
4867 : but with additional length and bias parameters, return the internal_fn
4868 : for that function, otherwise return IFN_LAST. */
4869 : internal_fn
4870 9985 : get_len_internal_fn (internal_fn fn)
4871 : {
4872 9985 : switch (fn)
4873 : {
4874 : #define DEF_INTERNAL_COND_FN(NAME, ...) \
4875 : case IFN_COND_##NAME: \
4876 : return IFN_COND_LEN_##NAME;
4877 : #define DEF_INTERNAL_SIGNED_COND_FN(NAME, ...) \
4878 : case IFN_COND_##NAME: \
4879 : return IFN_COND_LEN_##NAME;
4880 : #include "internal-fn.def"
4881 6599 : default:
4882 6599 : break;
4883 : }
4884 :
4885 6599 : switch (fn)
4886 : {
4887 : case IFN_MASK_LOAD:
4888 : return IFN_MASK_LEN_LOAD;
4889 : case IFN_MASK_LOAD_LANES:
4890 : return IFN_MASK_LEN_LOAD_LANES;
4891 : case IFN_MASK_GATHER_LOAD:
4892 : return IFN_MASK_LEN_GATHER_LOAD;
4893 : default:
4894 : return IFN_LAST;
4895 : }
4896 : }
4897 :
4898 : /* If IFN implements the conditional form of an unconditional internal
4899 : function, return that unconditional function, otherwise return IFN_LAST. */
4900 :
4901 : internal_fn
4902 3142371 : get_unconditional_internal_fn (internal_fn ifn)
4903 : {
4904 3142371 : switch (ifn)
4905 : {
4906 : #define CASE(NAME) \
4907 : case IFN_COND_##NAME: \
4908 : case IFN_COND_LEN_##NAME: \
4909 : return IFN_##NAME;
4910 : FOR_EACH_COND_FN_PAIR (CASE)
4911 : #undef CASE
4912 : default:
4913 : return IFN_LAST;
4914 : }
4915 : }
4916 :
4917 : /* Return true if STMT can be interpreted as a conditional tree code
4918 : operation of the form:
4919 :
4920 : LHS = COND ? OP (RHS1, ...) : ELSE;
4921 :
4922 : operating elementwise if the operands are vectors. This includes
4923 : the case of an all-true COND, so that the operation always happens.
4924 :
4925 : There is an alternative approach to interpret the STMT when the operands
4926 : are vectors which is the operation predicated by both conditional mask
4927 : and loop control length, the equivalent C code:
4928 :
4929 : for (int i = 0; i < NUNTIS; i++)
4930 : {
4931 : if (i < LEN + BIAS && COND[i])
4932 : LHS[i] = A[i] CODE B[i];
4933 : else
4934 : LHS[i] = ELSE[i];
4935 : }
4936 :
4937 : When returning true, set:
4938 :
4939 : - *COND_OUT to the condition COND, or to NULL_TREE if the condition
4940 : is known to be all-true
4941 : - *CODE_OUT to the tree code
4942 : - OPS[I] to operand I of *CODE_OUT
4943 : - *ELSE_OUT to the fallback value ELSE, or to NULL_TREE if the
4944 : condition is known to be all true.
4945 : - *LEN to the len argument if it COND_LEN_* operations or to NULL_TREE.
4946 : - *BIAS to the bias argument if it COND_LEN_* operations or to NULL_TREE. */
4947 :
4948 : bool
4949 40465 : can_interpret_as_conditional_op_p (gimple *stmt, tree *cond_out,
4950 : tree_code *code_out,
4951 : tree (&ops)[3], tree *else_out,
4952 : tree *len, tree *bias)
4953 : {
4954 40465 : *len = NULL_TREE;
4955 40465 : *bias = NULL_TREE;
4956 40465 : if (gassign *assign = dyn_cast <gassign *> (stmt))
4957 : {
4958 37685 : *cond_out = NULL_TREE;
4959 37685 : *code_out = gimple_assign_rhs_code (assign);
4960 37685 : ops[0] = gimple_assign_rhs1 (assign);
4961 37685 : ops[1] = gimple_assign_rhs2 (assign);
4962 37685 : ops[2] = gimple_assign_rhs3 (assign);
4963 37685 : *else_out = NULL_TREE;
4964 37685 : return true;
4965 : }
4966 2780 : if (gcall *call = dyn_cast <gcall *> (stmt))
4967 2205 : if (gimple_call_internal_p (call))
4968 : {
4969 2169 : internal_fn ifn = gimple_call_internal_fn (call);
4970 2169 : tree_code code = conditional_internal_fn_code (ifn);
4971 2169 : int len_index = internal_fn_len_index (ifn);
4972 2169 : int cond_nargs = len_index >= 0 ? 4 : 2;
4973 2169 : if (code != ERROR_MARK)
4974 : {
4975 216 : *cond_out = gimple_call_arg (call, 0);
4976 216 : *code_out = code;
4977 216 : unsigned int nops = gimple_call_num_args (call) - cond_nargs;
4978 864 : for (unsigned int i = 0; i < 3; ++i)
4979 648 : ops[i] = i < nops ? gimple_call_arg (call, i + 1) : NULL_TREE;
4980 216 : *else_out = gimple_call_arg (call, nops + 1);
4981 216 : if (len_index < 0)
4982 : {
4983 216 : if (integer_truep (*cond_out))
4984 : {
4985 0 : *cond_out = NULL_TREE;
4986 0 : *else_out = NULL_TREE;
4987 : }
4988 : }
4989 : else
4990 : {
4991 0 : *len = gimple_call_arg (call, len_index);
4992 0 : *bias = gimple_call_arg (call, len_index + 1);
4993 : }
4994 216 : return true;
4995 : }
4996 : }
4997 : return false;
4998 : }
4999 :
5000 : /* Return true if IFN is some form of load from memory. */
5001 :
5002 : bool
5003 1190611 : internal_load_fn_p (internal_fn fn)
5004 : {
5005 1190611 : switch (fn)
5006 : {
5007 : case IFN_MASK_LOAD:
5008 : case IFN_LOAD_LANES:
5009 : case IFN_MASK_LOAD_LANES:
5010 : case IFN_MASK_LEN_LOAD_LANES:
5011 : case IFN_GATHER_LOAD:
5012 : case IFN_MASK_GATHER_LOAD:
5013 : case IFN_MASK_LEN_GATHER_LOAD:
5014 : case IFN_LEN_LOAD:
5015 : case IFN_MASK_LEN_LOAD:
5016 : return true;
5017 :
5018 273825 : default:
5019 273825 : return false;
5020 : }
5021 : }
5022 :
5023 : /* Return true if IFN is some form of store to memory. */
5024 :
5025 : bool
5026 493556 : internal_store_fn_p (internal_fn fn)
5027 : {
5028 493556 : switch (fn)
5029 : {
5030 : case IFN_MASK_STORE:
5031 : case IFN_STORE_LANES:
5032 : case IFN_MASK_STORE_LANES:
5033 : case IFN_MASK_LEN_STORE_LANES:
5034 : case IFN_SCATTER_STORE:
5035 : case IFN_MASK_SCATTER_STORE:
5036 : case IFN_MASK_LEN_SCATTER_STORE:
5037 : case IFN_LEN_STORE:
5038 : case IFN_MASK_LEN_STORE:
5039 : return true;
5040 :
5041 482983 : default:
5042 482983 : return false;
5043 : }
5044 : }
5045 :
5046 : /* Return true if IFN is some form of gather load or scatter store. */
5047 :
5048 : bool
5049 40189 : internal_gather_scatter_fn_p (internal_fn fn)
5050 : {
5051 40189 : switch (fn)
5052 : {
5053 : case IFN_GATHER_LOAD:
5054 : case IFN_MASK_GATHER_LOAD:
5055 : case IFN_MASK_LEN_GATHER_LOAD:
5056 : case IFN_SCATTER_STORE:
5057 : case IFN_MASK_SCATTER_STORE:
5058 : case IFN_MASK_LEN_SCATTER_STORE:
5059 : return true;
5060 :
5061 40189 : default:
5062 40189 : return false;
5063 : }
5064 : }
5065 :
5066 : /* If FN takes a vector len argument, return the index of that argument,
5067 : otherwise return -1. */
5068 :
5069 : int
5070 3037050 : internal_fn_len_index (internal_fn fn)
5071 : {
5072 3037050 : switch (fn)
5073 : {
5074 : case IFN_LEN_LOAD:
5075 : return 3;
5076 : case IFN_LEN_STORE:
5077 : return 2;
5078 :
5079 : case IFN_MASK_LEN_SCATTER_STORE:
5080 : return 6;
5081 :
5082 : case IFN_MASK_LEN_STRIDED_LOAD:
5083 : return 5;
5084 :
5085 : case IFN_MASK_LEN_GATHER_LOAD:
5086 : return 7;
5087 :
5088 : case IFN_COND_LEN_FMA:
5089 : case IFN_COND_LEN_FMS:
5090 : case IFN_COND_LEN_FNMA:
5091 : case IFN_COND_LEN_FNMS:
5092 : return 5;
5093 :
5094 : case IFN_COND_LEN_ADD:
5095 : case IFN_COND_LEN_SUB:
5096 : case IFN_COND_LEN_MUL:
5097 : case IFN_COND_LEN_DIV:
5098 : case IFN_COND_LEN_MOD:
5099 : case IFN_COND_LEN_RDIV:
5100 : case IFN_COND_LEN_MIN:
5101 : case IFN_COND_LEN_MAX:
5102 : case IFN_COND_LEN_FMIN:
5103 : case IFN_COND_LEN_FMAX:
5104 : case IFN_COND_LEN_AND:
5105 : case IFN_COND_LEN_IOR:
5106 : case IFN_COND_LEN_XOR:
5107 : case IFN_COND_LEN_SHL:
5108 : case IFN_COND_LEN_SHR:
5109 : case IFN_MASK_LEN_STRIDED_STORE:
5110 : return 4;
5111 :
5112 : case IFN_COND_LEN_NEG:
5113 : case IFN_MASK_LEN_STORE:
5114 : case IFN_MASK_LEN_STORE_LANES:
5115 : case IFN_VCOND_MASK_LEN:
5116 : return 3;
5117 :
5118 : case IFN_MASK_LEN_LOAD:
5119 : case IFN_MASK_LEN_LOAD_LANES:
5120 : return 4;
5121 :
5122 : default:
5123 : return -1;
5124 : }
5125 : }
5126 :
5127 : /* If FN is an IFN_COND_* or IFN_COND_LEN_* function, return the index of the
5128 : argument that is used when the condition is false. Return -1 otherwise. */
5129 :
5130 : int
5131 62838 : internal_fn_else_index (internal_fn fn)
5132 : {
5133 62838 : switch (fn)
5134 : {
5135 : case IFN_COND_NEG:
5136 : case IFN_COND_NOT:
5137 : case IFN_COND_SQRT:
5138 : case IFN_COND_CEIL:
5139 : case IFN_COND_FLOOR:
5140 : case IFN_COND_ROUND:
5141 : case IFN_COND_RINT:
5142 : case IFN_COND_LEN_NEG:
5143 : case IFN_COND_LEN_NOT:
5144 : case IFN_COND_LEN_SQRT:
5145 : case IFN_COND_LEN_CEIL:
5146 : case IFN_COND_LEN_FLOOR:
5147 : case IFN_COND_LEN_ROUND:
5148 : case IFN_COND_LEN_RINT:
5149 : return 2;
5150 :
5151 : case IFN_LEN_LOAD:
5152 : return 2;
5153 :
5154 : case IFN_COND_ADD:
5155 : case IFN_COND_SUB:
5156 : case IFN_COND_MUL:
5157 : case IFN_COND_DIV:
5158 : case IFN_COND_MOD:
5159 : case IFN_COND_MIN:
5160 : case IFN_COND_MAX:
5161 : case IFN_COND_FMIN:
5162 : case IFN_COND_FMAX:
5163 : case IFN_COND_AND:
5164 : case IFN_COND_IOR:
5165 : case IFN_COND_XOR:
5166 : case IFN_COND_SHL:
5167 : case IFN_COND_SHR:
5168 : case IFN_COND_LEN_ADD:
5169 : case IFN_COND_LEN_SUB:
5170 : case IFN_COND_LEN_MUL:
5171 : case IFN_COND_LEN_DIV:
5172 : case IFN_COND_LEN_MOD:
5173 : case IFN_COND_LEN_MIN:
5174 : case IFN_COND_LEN_MAX:
5175 : case IFN_COND_LEN_FMIN:
5176 : case IFN_COND_LEN_FMAX:
5177 : case IFN_COND_LEN_AND:
5178 : case IFN_COND_LEN_IOR:
5179 : case IFN_COND_LEN_XOR:
5180 : case IFN_COND_LEN_SHL:
5181 : case IFN_COND_LEN_SHR:
5182 : return 3;
5183 :
5184 : case IFN_MASK_LOAD:
5185 : case IFN_MASK_LEN_LOAD:
5186 : case IFN_MASK_LOAD_LANES:
5187 : case IFN_MASK_LEN_LOAD_LANES:
5188 : return 3;
5189 :
5190 : case IFN_COND_FMA:
5191 : case IFN_COND_FMS:
5192 : case IFN_COND_FNMA:
5193 : case IFN_COND_FNMS:
5194 : case IFN_COND_LEN_FMA:
5195 : case IFN_COND_LEN_FMS:
5196 : case IFN_COND_LEN_FNMA:
5197 : case IFN_COND_LEN_FNMS:
5198 : case IFN_MASK_LEN_STRIDED_LOAD:
5199 : return 4;
5200 :
5201 : case IFN_MASK_GATHER_LOAD:
5202 : case IFN_MASK_LEN_GATHER_LOAD:
5203 : return 6;
5204 :
5205 : default:
5206 : return -1;
5207 : }
5208 :
5209 : return -1;
5210 : }
5211 :
5212 : /* If FN takes a vector mask argument, return the index of that argument,
5213 : otherwise return -1. */
5214 :
5215 : int
5216 192979 : internal_fn_mask_index (internal_fn fn)
5217 : {
5218 192979 : switch (fn)
5219 : {
5220 : case IFN_MASK_LOAD:
5221 : case IFN_MASK_LOAD_LANES:
5222 : case IFN_MASK_LEN_LOAD_LANES:
5223 : case IFN_MASK_STORE:
5224 : case IFN_MASK_STORE_LANES:
5225 : case IFN_MASK_LEN_STORE_LANES:
5226 : case IFN_MASK_LEN_LOAD:
5227 : case IFN_MASK_LEN_STORE:
5228 : return 2;
5229 :
5230 0 : case IFN_MASK_LEN_STRIDED_LOAD:
5231 0 : case IFN_MASK_LEN_STRIDED_STORE:
5232 0 : return 3;
5233 :
5234 0 : case IFN_MASK_GATHER_LOAD:
5235 0 : case IFN_MASK_SCATTER_STORE:
5236 0 : case IFN_MASK_LEN_GATHER_LOAD:
5237 0 : case IFN_MASK_LEN_SCATTER_STORE:
5238 0 : return 5;
5239 :
5240 : case IFN_VCOND_MASK:
5241 : case IFN_VCOND_MASK_LEN:
5242 : return 0;
5243 :
5244 154109 : default:
5245 154109 : return (conditional_internal_fn_code (fn) != ERROR_MARK
5246 154109 : || get_unconditional_internal_fn (fn) != IFN_LAST ? 0 : -1);
5247 : }
5248 : }
5249 :
5250 : /* If FN takes a value that should be stored to memory, return the index
5251 : of that argument, otherwise return -1. */
5252 :
5253 : int
5254 24747 : internal_fn_stored_value_index (internal_fn fn)
5255 : {
5256 24747 : switch (fn)
5257 : {
5258 : case IFN_MASK_LEN_STRIDED_STORE:
5259 : return 2;
5260 :
5261 : case IFN_MASK_STORE:
5262 : case IFN_MASK_STORE_LANES:
5263 : return 3;
5264 : case IFN_SCATTER_STORE:
5265 : case IFN_MASK_SCATTER_STORE:
5266 : case IFN_MASK_LEN_SCATTER_STORE:
5267 : return 4;
5268 :
5269 : case IFN_LEN_STORE:
5270 : return 4;
5271 :
5272 : case IFN_MASK_LEN_STORE:
5273 : case IFN_MASK_LEN_STORE_LANES:
5274 : return 5;
5275 :
5276 : default:
5277 : return -1;
5278 : }
5279 : }
5280 :
5281 : /* If FN has an alias pointer return its index, otherwise return -1. */
5282 :
5283 : int
5284 0 : internal_fn_alias_ptr_index (internal_fn fn)
5285 : {
5286 0 : switch (fn)
5287 : {
5288 : case IFN_MASK_LOAD:
5289 : case IFN_MASK_LEN_LOAD:
5290 : case IFN_GATHER_LOAD:
5291 : case IFN_MASK_GATHER_LOAD:
5292 : case IFN_MASK_LEN_GATHER_LOAD:
5293 : case IFN_SCATTER_STORE:
5294 : case IFN_MASK_SCATTER_STORE:
5295 : case IFN_MASK_LEN_SCATTER_STORE:
5296 : return 1;
5297 :
5298 0 : default:
5299 0 : return -1;
5300 : }
5301 : }
5302 :
5303 : /* If FN is a gather/scatter return the index of its offset argument,
5304 : otherwise return -1. */
5305 :
5306 : int
5307 0 : internal_fn_offset_index (internal_fn fn)
5308 : {
5309 0 : if (!internal_gather_scatter_fn_p (fn))
5310 : return -1;
5311 :
5312 0 : switch (fn)
5313 : {
5314 : case IFN_GATHER_LOAD:
5315 : case IFN_MASK_GATHER_LOAD:
5316 : case IFN_MASK_LEN_GATHER_LOAD:
5317 : case IFN_SCATTER_STORE:
5318 : case IFN_MASK_SCATTER_STORE:
5319 : case IFN_MASK_LEN_SCATTER_STORE:
5320 : return 2;
5321 :
5322 : default:
5323 : return -1;
5324 : }
5325 : }
5326 :
5327 : /* If FN is a gather/scatter return the index of its scale argument,
5328 : otherwise return -1. */
5329 :
5330 : int
5331 0 : internal_fn_scale_index (internal_fn fn)
5332 : {
5333 0 : if (!internal_gather_scatter_fn_p (fn))
5334 : return -1;
5335 :
5336 0 : switch (fn)
5337 : {
5338 : case IFN_GATHER_LOAD:
5339 : case IFN_MASK_GATHER_LOAD:
5340 : case IFN_MASK_LEN_GATHER_LOAD:
5341 : case IFN_SCATTER_STORE:
5342 : case IFN_MASK_SCATTER_STORE:
5343 : case IFN_MASK_LEN_SCATTER_STORE:
5344 : return 3;
5345 :
5346 : default:
5347 : return -1;
5348 : }
5349 : }
5350 :
5351 : /* Store all supported else values for the optab referred to by ICODE
5352 : in ELSE_VALS. The index of the else operand must be specified in
5353 : ELSE_INDEX. */
5354 :
5355 : void
5356 45974 : get_supported_else_vals (enum insn_code icode, unsigned else_index,
5357 : vec<int> &else_vals)
5358 : {
5359 45974 : const struct insn_data_d *data = &insn_data[icode];
5360 45974 : if ((int) else_index >= data->n_operands || (int) else_index == -1)
5361 : return;
5362 :
5363 45974 : machine_mode else_mode = data->operand[else_index].mode;
5364 :
5365 45974 : else_vals.truncate (0);
5366 :
5367 : /* For now we only support else values of 0, -1, and "undefined". */
5368 45974 : if (insn_operand_matches (icode, else_index, CONST0_RTX (else_mode)))
5369 45974 : else_vals.safe_push (MASK_LOAD_ELSE_ZERO);
5370 :
5371 45974 : if (insn_operand_matches (icode, else_index, gen_rtx_SCRATCH (else_mode)))
5372 0 : else_vals.safe_push (MASK_LOAD_ELSE_UNDEFINED);
5373 :
5374 45974 : if (GET_MODE_CLASS (else_mode) == MODE_VECTOR_INT
5375 45974 : && insn_operand_matches (icode, else_index, CONSTM1_RTX (else_mode)))
5376 0 : else_vals.safe_push (MASK_LOAD_ELSE_M1);
5377 : }
5378 :
5379 : /* Return true if the else value ELSE_VAL (one of MASK_LOAD_ELSE_ZERO,
5380 : MASK_LOAD_ELSE_M1, and MASK_LOAD_ELSE_UNDEFINED) is valid fo the optab
5381 : referred to by ICODE. The index of the else operand must be specified
5382 : in ELSE_INDEX. */
5383 :
5384 : bool
5385 0 : supported_else_val_p (enum insn_code icode, unsigned else_index, int else_val)
5386 : {
5387 0 : if (else_val != MASK_LOAD_ELSE_ZERO && else_val != MASK_LOAD_ELSE_M1
5388 0 : && else_val != MASK_LOAD_ELSE_UNDEFINED)
5389 0 : gcc_unreachable ();
5390 :
5391 0 : auto_vec<int> else_vals;
5392 0 : get_supported_else_vals (icode, else_index, else_vals);
5393 0 : return else_vals.contains (else_val);
5394 0 : }
5395 :
5396 : /* Return true if the target supports gather load or scatter store function
5397 : IFN. For loads, VECTOR_TYPE is the vector type of the load result,
5398 : while for stores it is the vector type of the stored data argument.
5399 : MEMORY_ELEMENT_TYPE is the type of the memory elements being loaded
5400 : or stored. OFFSET_VECTOR_TYPE is the vector type that holds the
5401 : offset from the shared base address of each loaded or stored element.
5402 : SCALE is the amount by which these offsets should be multiplied
5403 : *after* they have been extended to address width.
5404 : If the target supports the gather load the supported else values
5405 : will be added to the vector ELSVAL points to if it is nonzero. */
5406 :
5407 : bool
5408 4226612 : internal_gather_scatter_fn_supported_p (internal_fn ifn, tree vector_type,
5409 : tree memory_element_type,
5410 : tree offset_vector_type, int scale,
5411 : vec<int> *elsvals)
5412 : {
5413 4226612 : if (!tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (vector_type)),
5414 4226612 : TYPE_SIZE (memory_element_type)))
5415 : return false;
5416 4226612 : if (maybe_ne (TYPE_VECTOR_SUBPARTS (vector_type),
5417 8453224 : TYPE_VECTOR_SUBPARTS (offset_vector_type)))
5418 : return false;
5419 1141270 : optab optab = direct_internal_fn_optab (ifn);
5420 1141270 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (vector_type),
5421 1141270 : TYPE_MODE (offset_vector_type));
5422 1141270 : int output_ops = internal_load_fn_p (ifn) ? 1 : 0;
5423 1141270 : bool unsigned_p = TYPE_UNSIGNED (TREE_TYPE (offset_vector_type));
5424 1141270 : bool ok = icode != CODE_FOR_nothing
5425 0 : && insn_operand_matches (icode, 2 + output_ops, GEN_INT (unsigned_p))
5426 1141270 : && insn_operand_matches (icode, 3 + output_ops, GEN_INT (scale));
5427 :
5428 1141270 : if (ok && elsvals)
5429 0 : get_supported_else_vals
5430 0 : (icode, internal_fn_else_index (IFN_MASK_GATHER_LOAD), *elsvals);
5431 :
5432 : return ok;
5433 : }
5434 :
5435 : /* Return true if the target supports a strided load/store function IFN
5436 : with VECTOR_TYPE. If supported and ELSVALS is nonzero the supported else
5437 : values will be added to the vector ELSVALS points to. */
5438 :
5439 : bool
5440 2540 : internal_strided_fn_supported_p (internal_fn ifn, tree vector_type,
5441 : vec<int> *elsvals)
5442 : {
5443 2540 : machine_mode mode = TYPE_MODE (vector_type);
5444 2540 : optab optab = direct_internal_fn_optab (ifn);
5445 2540 : insn_code icode = direct_optab_handler (optab, mode);
5446 :
5447 2540 : bool ok = icode != CODE_FOR_nothing;
5448 :
5449 2540 : if (ok && elsvals)
5450 0 : get_supported_else_vals (icode, internal_fn_else_index (ifn), *elsvals);
5451 :
5452 2540 : return ok;
5453 : }
5454 :
5455 : /* Return true if the target supports IFN_CHECK_{RAW,WAR}_PTRS function IFN
5456 : for pointers of type TYPE when the accesses have LENGTH bytes and their
5457 : common byte alignment is ALIGN. */
5458 :
5459 : bool
5460 5266 : internal_check_ptrs_fn_supported_p (internal_fn ifn, tree type,
5461 : poly_uint64 length, unsigned int align)
5462 : {
5463 5266 : machine_mode mode = TYPE_MODE (type);
5464 5266 : optab optab = direct_internal_fn_optab (ifn);
5465 5266 : insn_code icode = direct_optab_handler (optab, mode);
5466 5266 : if (icode == CODE_FOR_nothing)
5467 : return false;
5468 0 : rtx length_rtx = immed_wide_int_const (length, mode);
5469 0 : return (insn_operand_matches (icode, 3, length_rtx)
5470 0 : && insn_operand_matches (icode, 4, GEN_INT (align)));
5471 : }
5472 :
5473 : /* Return the supported bias for IFN which is either IFN_{LEN_,MASK_LEN_,}LOAD
5474 : or IFN_{LEN_,MASK_LEN_,}STORE. For now we only support the biases of 0 and
5475 : -1 (in case 0 is not an allowable length for {len_,mask_len_}load or
5476 : {len_,mask_len_}store). If none of the biases match what the backend
5477 : provides, return VECT_PARTIAL_BIAS_UNSUPPORTED. */
5478 :
5479 : signed char
5480 0 : internal_len_load_store_bias (internal_fn ifn, machine_mode mode)
5481 : {
5482 0 : optab optab = direct_internal_fn_optab (ifn);
5483 0 : insn_code icode = direct_optab_handler (optab, mode);
5484 0 : int bias_idx = internal_fn_len_index (ifn) + 1;
5485 :
5486 0 : if (icode == CODE_FOR_nothing)
5487 : {
5488 0 : machine_mode mask_mode;
5489 0 : if (!targetm.vectorize.get_mask_mode (mode).exists (&mask_mode))
5490 0 : return VECT_PARTIAL_BIAS_UNSUPPORTED;
5491 0 : if (ifn == IFN_LEN_LOAD)
5492 : {
5493 : /* Try MASK_LEN_LOAD. */
5494 0 : optab = direct_internal_fn_optab (IFN_MASK_LEN_LOAD);
5495 0 : bias_idx = internal_fn_len_index (IFN_MASK_LEN_LOAD) + 1;
5496 : }
5497 : else
5498 : {
5499 : /* Try MASK_LEN_STORE. */
5500 0 : optab = direct_internal_fn_optab (IFN_MASK_LEN_STORE);
5501 0 : bias_idx = internal_fn_len_index (IFN_MASK_LEN_STORE) + 1;
5502 : }
5503 0 : icode = convert_optab_handler (optab, mode, mask_mode);
5504 : }
5505 :
5506 0 : if (icode != CODE_FOR_nothing)
5507 : {
5508 : /* For now we only support biases of 0 or -1. Try both of them. */
5509 0 : if (insn_operand_matches (icode, bias_idx, GEN_INT (0)))
5510 : return 0;
5511 0 : if (insn_operand_matches (icode, bias_idx, GEN_INT (-1)))
5512 : return -1;
5513 : }
5514 :
5515 : return VECT_PARTIAL_BIAS_UNSUPPORTED;
5516 : }
5517 :
5518 : /* Expand STMT as though it were a call to internal function FN. */
5519 :
5520 : void
5521 255244 : expand_internal_call (internal_fn fn, gcall *stmt)
5522 : {
5523 255244 : internal_fn_expanders[fn] (fn, stmt);
5524 255244 : }
5525 :
5526 : /* Expand STMT, which is a call to internal function FN. */
5527 :
5528 : void
5529 221013 : expand_internal_call (gcall *stmt)
5530 : {
5531 221013 : expand_internal_call (gimple_call_internal_fn (stmt), stmt);
5532 221013 : }
5533 :
5534 : /* If TYPE is a vector type, return true if IFN is a direct internal
5535 : function that is supported for that type. If TYPE is a scalar type,
5536 : return true if IFN is a direct internal function that is supported for
5537 : the target's preferred vector version of TYPE. */
5538 :
5539 : bool
5540 14854 : vectorized_internal_fn_supported_p (internal_fn ifn, tree type)
5541 : {
5542 14854 : if (VECTOR_MODE_P (TYPE_MODE (type)))
5543 8603 : return direct_internal_fn_supported_p (ifn, type, OPTIMIZE_FOR_SPEED);
5544 :
5545 6251 : scalar_mode smode;
5546 6251 : if (VECTOR_TYPE_P (type)
5547 6251 : || !is_a <scalar_mode> (TYPE_MODE (type), &smode))
5548 11 : return false;
5549 :
5550 6240 : machine_mode vmode = targetm.vectorize.preferred_simd_mode (smode);
5551 6240 : if (VECTOR_MODE_P (vmode))
5552 : {
5553 6203 : tree vectype = build_vector_type_for_mode (type, vmode);
5554 6203 : if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
5555 : return true;
5556 : }
5557 :
5558 4230 : auto_vector_modes vector_modes;
5559 4230 : targetm.vectorize.autovectorize_vector_modes (&vector_modes, true);
5560 26394 : for (machine_mode base_mode : vector_modes)
5561 13704 : if (related_vector_mode (base_mode, smode).exists (&vmode))
5562 : {
5563 12054 : tree vectype = build_vector_type_for_mode (type, vmode);
5564 12054 : if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
5565 : return true;
5566 : }
5567 :
5568 : return false;
5569 4230 : }
5570 :
5571 : void
5572 0 : expand_SHUFFLEVECTOR (internal_fn, gcall *)
5573 : {
5574 0 : gcc_unreachable ();
5575 : }
5576 :
5577 : void
5578 0 : expand_PHI (internal_fn, gcall *)
5579 : {
5580 0 : gcc_unreachable ();
5581 : }
5582 :
5583 : void
5584 279 : expand_SPACESHIP (internal_fn, gcall *stmt)
5585 : {
5586 279 : tree lhs = gimple_call_lhs (stmt);
5587 279 : tree rhs1 = gimple_call_arg (stmt, 0);
5588 279 : tree rhs2 = gimple_call_arg (stmt, 1);
5589 279 : tree rhs3 = gimple_call_arg (stmt, 2);
5590 279 : tree type = TREE_TYPE (rhs1);
5591 :
5592 279 : do_pending_stack_adjust ();
5593 :
5594 279 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
5595 279 : rtx op1 = expand_normal (rhs1);
5596 279 : rtx op2 = expand_normal (rhs2);
5597 279 : rtx op3 = expand_normal (rhs3);
5598 :
5599 279 : class expand_operand ops[4];
5600 279 : create_call_lhs_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (lhs)));
5601 279 : create_input_operand (&ops[1], op1, TYPE_MODE (type));
5602 279 : create_input_operand (&ops[2], op2, TYPE_MODE (type));
5603 279 : create_input_operand (&ops[3], op3, TYPE_MODE (TREE_TYPE (rhs3)));
5604 279 : insn_code icode = optab_handler (spaceship_optab, TYPE_MODE (type));
5605 279 : expand_insn (icode, 4, ops);
5606 279 : assign_call_lhs (lhs, target, &ops[0]);
5607 279 : }
5608 :
5609 : void
5610 0 : expand_ASSUME (internal_fn, gcall *)
5611 : {
5612 0 : }
5613 :
5614 : void
5615 0 : expand_MASK_CALL (internal_fn, gcall *)
5616 : {
5617 : /* This IFN should only exist between ifcvt and vect passes. */
5618 0 : gcc_unreachable ();
5619 : }
5620 :
5621 : void
5622 1566 : expand_MULBITINT (internal_fn, gcall *stmt)
5623 : {
5624 1566 : rtx_mode_t args[6];
5625 10962 : for (int i = 0; i < 6; i++)
5626 9396 : args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
5627 18792 : (i & 1) ? SImode : ptr_mode);
5628 1566 : rtx fun = init_one_libfunc ("__mulbitint3");
5629 1566 : emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 6, args);
5630 1566 : }
5631 :
5632 : void
5633 139 : expand_DIVMODBITINT (internal_fn, gcall *stmt)
5634 : {
5635 139 : rtx_mode_t args[8];
5636 1251 : for (int i = 0; i < 8; i++)
5637 1112 : args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
5638 2224 : (i & 1) ? SImode : ptr_mode);
5639 139 : rtx fun = init_one_libfunc ("__divmodbitint4");
5640 139 : emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 8, args);
5641 139 : }
5642 :
5643 : void
5644 167 : expand_FLOATTOBITINT (internal_fn, gcall *stmt)
5645 : {
5646 167 : machine_mode mode = TYPE_MODE (TREE_TYPE (gimple_call_arg (stmt, 2)));
5647 167 : rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
5648 167 : rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
5649 167 : rtx arg2 = expand_normal (gimple_call_arg (stmt, 2));
5650 167 : const char *mname = GET_MODE_NAME (mode);
5651 167 : unsigned mname_len = strlen (mname);
5652 167 : int len = 12 + mname_len;
5653 167 : if (DECIMAL_FLOAT_MODE_P (mode))
5654 57 : len += 4;
5655 167 : char *libfunc_name = XALLOCAVEC (char, len);
5656 167 : char *p = libfunc_name;
5657 167 : const char *q;
5658 167 : if (DECIMAL_FLOAT_MODE_P (mode))
5659 : {
5660 : #if ENABLE_DECIMAL_BID_FORMAT
5661 57 : memcpy (p, "__bid_fix", 9);
5662 : #else
5663 : memcpy (p, "__dpd_fix", 9);
5664 : #endif
5665 57 : p += 9;
5666 : }
5667 : else
5668 : {
5669 110 : memcpy (p, "__fix", 5);
5670 110 : p += 5;
5671 : }
5672 501 : for (q = mname; *q; q++)
5673 334 : *p++ = TOLOWER (*q);
5674 167 : memcpy (p, "bitint", 7);
5675 167 : rtx fun = init_one_libfunc (libfunc_name);
5676 167 : emit_library_call (fun, LCT_NORMAL, VOIDmode, arg0, ptr_mode, arg1,
5677 : SImode, arg2, mode);
5678 167 : }
5679 :
5680 : void
5681 138 : expand_BITINTTOFLOAT (internal_fn, gcall *stmt)
5682 : {
5683 138 : tree lhs = gimple_call_lhs (stmt);
5684 138 : if (!lhs)
5685 : return;
5686 138 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
5687 138 : rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
5688 138 : rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
5689 138 : const char *mname = GET_MODE_NAME (mode);
5690 138 : unsigned mname_len = strlen (mname);
5691 138 : int len = 14 + mname_len;
5692 138 : if (DECIMAL_FLOAT_MODE_P (mode))
5693 17 : len += 4;
5694 138 : char *libfunc_name = XALLOCAVEC (char, len);
5695 138 : char *p = libfunc_name;
5696 138 : const char *q;
5697 138 : if (DECIMAL_FLOAT_MODE_P (mode))
5698 : {
5699 : #if ENABLE_DECIMAL_BID_FORMAT
5700 17 : memcpy (p, "__bid_floatbitint", 17);
5701 : #else
5702 : memcpy (p, "__dpd_floatbitint", 17);
5703 : #endif
5704 17 : p += 17;
5705 : }
5706 : else
5707 : {
5708 121 : memcpy (p, "__floatbitint", 13);
5709 121 : p += 13;
5710 : }
5711 414 : for (q = mname; *q; q++)
5712 276 : *p++ = TOLOWER (*q);
5713 138 : *p = '\0';
5714 138 : rtx fun = init_one_libfunc (libfunc_name);
5715 138 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
5716 138 : rtx val = emit_library_call_value (fun, target, LCT_PURE, mode,
5717 : arg0, ptr_mode, arg1, SImode);
5718 138 : if (val != target)
5719 0 : emit_move_insn (target, val);
5720 : }
5721 :
5722 : static bool
5723 7258 : expand_bitquery (internal_fn fn, gcall *stmt)
5724 : {
5725 7258 : tree lhs = gimple_call_lhs (stmt);
5726 7258 : if (lhs == NULL_TREE)
5727 : return false;
5728 7252 : tree arg = gimple_call_arg (stmt, 0);
5729 7252 : if (TREE_CODE (arg) == INTEGER_CST)
5730 : {
5731 0 : tree ret = fold_const_call (as_combined_fn (fn), TREE_TYPE (arg), arg);
5732 0 : gcc_checking_assert (ret && TREE_CODE (ret) == INTEGER_CST);
5733 0 : expand_assignment (lhs, ret, false);
5734 0 : return false;
5735 : }
5736 : return true;
5737 : }
5738 :
5739 : void
5740 1 : expand_CLRSB (internal_fn fn, gcall *stmt)
5741 : {
5742 1 : if (expand_bitquery (fn, stmt))
5743 0 : expand_unary_optab_fn (fn, stmt, clrsb_optab);
5744 1 : }
5745 :
5746 : void
5747 5889 : expand_CLZ (internal_fn fn, gcall *stmt)
5748 : {
5749 5889 : if (expand_bitquery (fn, stmt))
5750 5888 : expand_unary_optab_fn (fn, stmt, clz_optab);
5751 5889 : }
5752 :
5753 : void
5754 854 : expand_CTZ (internal_fn fn, gcall *stmt)
5755 : {
5756 854 : if (expand_bitquery (fn, stmt))
5757 853 : expand_unary_optab_fn (fn, stmt, ctz_optab);
5758 854 : }
5759 :
5760 : void
5761 132 : expand_FFS (internal_fn fn, gcall *stmt)
5762 : {
5763 132 : if (expand_bitquery (fn, stmt))
5764 131 : expand_unary_optab_fn (fn, stmt, ffs_optab);
5765 132 : }
5766 :
5767 : void
5768 165 : expand_PARITY (internal_fn fn, gcall *stmt)
5769 : {
5770 165 : if (expand_bitquery (fn, stmt))
5771 164 : expand_unary_optab_fn (fn, stmt, parity_optab);
5772 165 : }
5773 :
5774 : void
5775 217 : expand_POPCOUNT (internal_fn fn, gcall *stmt)
5776 : {
5777 217 : if (!expand_bitquery (fn, stmt))
5778 : return;
5779 216 : if (gimple_call_num_args (stmt) == 1)
5780 : {
5781 208 : expand_unary_optab_fn (fn, stmt, popcount_optab);
5782 208 : return;
5783 : }
5784 : /* If .POPCOUNT call has 2 arguments, match_single_bit_test marked it
5785 : because the result is only used in an equality comparison against 1.
5786 : Use rtx costs in that case to determine if .POPCOUNT (arg) == 1
5787 : or (arg ^ (arg - 1)) > arg - 1 is cheaper.
5788 : If .POPCOUNT second argument is 0, we additionally know that arg
5789 : is non-zero, so use arg & (arg - 1) == 0 instead.
5790 : If .POPCOUNT second argument is -1, the comparison was either `<= 1`
5791 : or `> 1`. */
5792 8 : bool speed_p = optimize_insn_for_speed_p ();
5793 8 : tree lhs = gimple_call_lhs (stmt);
5794 8 : tree arg = gimple_call_arg (stmt, 0);
5795 8 : bool nonzero_arg = integer_zerop (gimple_call_arg (stmt, 1));
5796 8 : bool was_le = integer_minus_onep (gimple_call_arg (stmt, 1));
5797 8 : if (was_le)
5798 0 : nonzero_arg = true;
5799 8 : tree type = TREE_TYPE (arg);
5800 8 : machine_mode mode = TYPE_MODE (type);
5801 8 : machine_mode lhsmode = TYPE_MODE (TREE_TYPE (lhs));
5802 8 : do_pending_stack_adjust ();
5803 8 : start_sequence ();
5804 8 : expand_unary_optab_fn (fn, stmt, popcount_optab);
5805 8 : rtx_insn *popcount_insns = end_sequence ();
5806 8 : start_sequence ();
5807 8 : rtx plhs = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
5808 8 : rtx pcmp = emit_store_flag (NULL_RTX, EQ, plhs, const1_rtx, lhsmode, 0, 0);
5809 8 : if (pcmp == NULL_RTX)
5810 : {
5811 0 : fail:
5812 0 : end_sequence ();
5813 0 : emit_insn (popcount_insns);
5814 0 : return;
5815 : }
5816 8 : rtx_insn *popcount_cmp_insns = end_sequence ();
5817 8 : start_sequence ();
5818 8 : rtx op0 = expand_normal (arg);
5819 8 : rtx argm1 = expand_simple_binop (mode, PLUS, op0, constm1_rtx, NULL_RTX,
5820 : 1, OPTAB_WIDEN);
5821 8 : if (argm1 == NULL_RTX)
5822 0 : goto fail;
5823 12 : rtx argxorargm1 = expand_simple_binop (mode, nonzero_arg ? AND : XOR, op0,
5824 : argm1, NULL_RTX, 1, OPTAB_WIDEN);
5825 8 : if (argxorargm1 == NULL_RTX)
5826 0 : goto fail;
5827 8 : rtx cmp;
5828 8 : if (nonzero_arg)
5829 4 : cmp = emit_store_flag (NULL_RTX, EQ, argxorargm1, const0_rtx, mode, 1, 1);
5830 : else
5831 4 : cmp = emit_store_flag (NULL_RTX, GTU, argxorargm1, argm1, mode, 1, 1);
5832 8 : if (cmp == NULL_RTX)
5833 0 : goto fail;
5834 8 : rtx_insn *cmp_insns = end_sequence ();
5835 8 : unsigned popcount_cost = (seq_cost (popcount_insns, speed_p)
5836 8 : + seq_cost (popcount_cmp_insns, speed_p));
5837 8 : unsigned cmp_cost = seq_cost (cmp_insns, speed_p);
5838 :
5839 8 : if (dump_file && (dump_flags & TDF_DETAILS))
5840 0 : fprintf(dump_file, "popcount == 1: popcount cost: %u; cmp cost: %u\n",
5841 : popcount_cost, cmp_cost);
5842 :
5843 8 : if (popcount_cost <= cmp_cost)
5844 8 : emit_insn (popcount_insns);
5845 : else
5846 : {
5847 0 : start_sequence ();
5848 0 : emit_insn (cmp_insns);
5849 0 : plhs = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
5850 0 : if (GET_MODE (cmp) != GET_MODE (plhs))
5851 0 : cmp = convert_to_mode (GET_MODE (plhs), cmp, 1);
5852 : /* For `<= 1`, we need to produce `2 - cmp` or `cmp ? 1 : 2` as that
5853 : then gets compared against 1 and we need the false case to be 2. */
5854 0 : if (was_le)
5855 : {
5856 0 : cmp = expand_simple_binop (GET_MODE (cmp), MINUS, const2_rtx,
5857 : cmp, NULL_RTX, 1, OPTAB_WIDEN);
5858 0 : if (!cmp)
5859 0 : goto fail;
5860 : }
5861 0 : emit_move_insn (plhs, cmp);
5862 0 : rtx_insn *all_insns = end_sequence ();
5863 0 : emit_insn (all_insns);
5864 : }
5865 : }
|