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