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