xref: /dflybsd-src/contrib/gcc-8.0/gcc/internal-fn.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj /* Internal functions.
2*38fd1498Szrj    Copyright (C) 2011-2018 Free Software Foundation, Inc.
3*38fd1498Szrj 
4*38fd1498Szrj This file is part of GCC.
5*38fd1498Szrj 
6*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
7*38fd1498Szrj the terms of the GNU General Public License as published by the Free
8*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
9*38fd1498Szrj version.
10*38fd1498Szrj 
11*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14*38fd1498Szrj for more details.
15*38fd1498Szrj 
16*38fd1498Szrj You should have received a copy of the GNU General Public License
17*38fd1498Szrj along with GCC; see the file COPYING3.  If not see
18*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
19*38fd1498Szrj 
20*38fd1498Szrj #include "config.h"
21*38fd1498Szrj #include "system.h"
22*38fd1498Szrj #include "coretypes.h"
23*38fd1498Szrj #include "backend.h"
24*38fd1498Szrj #include "target.h"
25*38fd1498Szrj #include "rtl.h"
26*38fd1498Szrj #include "tree.h"
27*38fd1498Szrj #include "gimple.h"
28*38fd1498Szrj #include "predict.h"
29*38fd1498Szrj #include "stringpool.h"
30*38fd1498Szrj #include "tree-vrp.h"
31*38fd1498Szrj #include "tree-ssanames.h"
32*38fd1498Szrj #include "expmed.h"
33*38fd1498Szrj #include "memmodel.h"
34*38fd1498Szrj #include "optabs.h"
35*38fd1498Szrj #include "emit-rtl.h"
36*38fd1498Szrj #include "diagnostic-core.h"
37*38fd1498Szrj #include "fold-const.h"
38*38fd1498Szrj #include "internal-fn.h"
39*38fd1498Szrj #include "stor-layout.h"
40*38fd1498Szrj #include "dojump.h"
41*38fd1498Szrj #include "expr.h"
42*38fd1498Szrj #include "stringpool.h"
43*38fd1498Szrj #include "attribs.h"
44*38fd1498Szrj #include "asan.h"
45*38fd1498Szrj #include "ubsan.h"
46*38fd1498Szrj #include "recog.h"
47*38fd1498Szrj #include "builtins.h"
48*38fd1498Szrj #include "optabs-tree.h"
49*38fd1498Szrj #include "gimple-ssa.h"
50*38fd1498Szrj #include "tree-phinodes.h"
51*38fd1498Szrj #include "ssa-iterators.h"
52*38fd1498Szrj 
53*38fd1498Szrj /* The names of each internal function, indexed by function number.  */
54*38fd1498Szrj const char *const internal_fn_name_array[] = {
55*38fd1498Szrj #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) #CODE,
56*38fd1498Szrj #include "internal-fn.def"
57*38fd1498Szrj   "<invalid-fn>"
58*38fd1498Szrj };
59*38fd1498Szrj 
60*38fd1498Szrj /* The ECF_* flags of each internal function, indexed by function number.  */
61*38fd1498Szrj const int internal_fn_flags_array[] = {
62*38fd1498Szrj #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) FLAGS,
63*38fd1498Szrj #include "internal-fn.def"
64*38fd1498Szrj   0
65*38fd1498Szrj };
66*38fd1498Szrj 
67*38fd1498Szrj /* Fnspec of each internal function, indexed by function number.  */
68*38fd1498Szrj const_tree internal_fn_fnspec_array[IFN_LAST + 1];
69*38fd1498Szrj 
70*38fd1498Szrj void
init_internal_fns()71*38fd1498Szrj init_internal_fns ()
72*38fd1498Szrj {
73*38fd1498Szrj #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
74*38fd1498Szrj   if (FNSPEC) internal_fn_fnspec_array[IFN_##CODE] = \
75*38fd1498Szrj     build_string ((int) sizeof (FNSPEC), FNSPEC ? FNSPEC : "");
76*38fd1498Szrj #include "internal-fn.def"
77*38fd1498Szrj   internal_fn_fnspec_array[IFN_LAST] = 0;
78*38fd1498Szrj }
79*38fd1498Szrj 
80*38fd1498Szrj /* Create static initializers for the information returned by
81*38fd1498Szrj    direct_internal_fn.  */
82*38fd1498Szrj #define not_direct { -2, -2, false }
83*38fd1498Szrj #define mask_load_direct { -1, 2, false }
84*38fd1498Szrj #define load_lanes_direct { -1, -1, false }
85*38fd1498Szrj #define mask_load_lanes_direct { -1, -1, false }
86*38fd1498Szrj #define gather_load_direct { -1, -1, false }
87*38fd1498Szrj #define mask_store_direct { 3, 2, false }
88*38fd1498Szrj #define store_lanes_direct { 0, 0, false }
89*38fd1498Szrj #define mask_store_lanes_direct { 0, 0, false }
90*38fd1498Szrj #define scatter_store_direct { 3, 3, false }
91*38fd1498Szrj #define unary_direct { 0, 0, true }
92*38fd1498Szrj #define binary_direct { 0, 0, true }
93*38fd1498Szrj #define cond_unary_direct { 1, 1, true }
94*38fd1498Szrj #define cond_binary_direct { 1, 1, true }
95*38fd1498Szrj #define while_direct { 0, 2, false }
96*38fd1498Szrj #define fold_extract_direct { 2, 2, false }
97*38fd1498Szrj #define fold_left_direct { 1, 1, false }
98*38fd1498Szrj 
99*38fd1498Szrj const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1] = {
100*38fd1498Szrj #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) not_direct,
101*38fd1498Szrj #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) TYPE##_direct,
102*38fd1498Szrj #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
103*38fd1498Szrj 				     UNSIGNED_OPTAB, TYPE) TYPE##_direct,
104*38fd1498Szrj #include "internal-fn.def"
105*38fd1498Szrj   not_direct
106*38fd1498Szrj };
107*38fd1498Szrj 
108*38fd1498Szrj /* ARRAY_TYPE is an array of vector modes.  Return the associated insn
109*38fd1498Szrj    for load-lanes-style optab OPTAB, or CODE_FOR_nothing if none.  */
110*38fd1498Szrj 
111*38fd1498Szrj static enum insn_code
get_multi_vector_move(tree array_type,convert_optab optab)112*38fd1498Szrj get_multi_vector_move (tree array_type, convert_optab optab)
113*38fd1498Szrj {
114*38fd1498Szrj   machine_mode imode;
115*38fd1498Szrj   machine_mode vmode;
116*38fd1498Szrj 
117*38fd1498Szrj   gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
118*38fd1498Szrj   imode = TYPE_MODE (array_type);
119*38fd1498Szrj   vmode = TYPE_MODE (TREE_TYPE (array_type));
120*38fd1498Szrj 
121*38fd1498Szrj   return convert_optab_handler (optab, imode, vmode);
122*38fd1498Szrj }
123*38fd1498Szrj 
124*38fd1498Szrj /* Expand LOAD_LANES call STMT using optab OPTAB.  */
125*38fd1498Szrj 
126*38fd1498Szrj static void
expand_load_lanes_optab_fn(internal_fn,gcall * stmt,convert_optab optab)127*38fd1498Szrj expand_load_lanes_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
128*38fd1498Szrj {
129*38fd1498Szrj   struct expand_operand ops[2];
130*38fd1498Szrj   tree type, lhs, rhs;
131*38fd1498Szrj   rtx target, mem;
132*38fd1498Szrj 
133*38fd1498Szrj   lhs = gimple_call_lhs (stmt);
134*38fd1498Szrj   rhs = gimple_call_arg (stmt, 0);
135*38fd1498Szrj   type = TREE_TYPE (lhs);
136*38fd1498Szrj 
137*38fd1498Szrj   target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
138*38fd1498Szrj   mem = expand_normal (rhs);
139*38fd1498Szrj 
140*38fd1498Szrj   gcc_assert (MEM_P (mem));
141*38fd1498Szrj   PUT_MODE (mem, TYPE_MODE (type));
142*38fd1498Szrj 
143*38fd1498Szrj   create_output_operand (&ops[0], target, TYPE_MODE (type));
144*38fd1498Szrj   create_fixed_operand (&ops[1], mem);
145*38fd1498Szrj   expand_insn (get_multi_vector_move (type, optab), 2, ops);
146*38fd1498Szrj }
147*38fd1498Szrj 
148*38fd1498Szrj /* Expand STORE_LANES call STMT using optab OPTAB.  */
149*38fd1498Szrj 
150*38fd1498Szrj static void
expand_store_lanes_optab_fn(internal_fn,gcall * stmt,convert_optab optab)151*38fd1498Szrj expand_store_lanes_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
152*38fd1498Szrj {
153*38fd1498Szrj   struct expand_operand ops[2];
154*38fd1498Szrj   tree type, lhs, rhs;
155*38fd1498Szrj   rtx target, reg;
156*38fd1498Szrj 
157*38fd1498Szrj   lhs = gimple_call_lhs (stmt);
158*38fd1498Szrj   rhs = gimple_call_arg (stmt, 0);
159*38fd1498Szrj   type = TREE_TYPE (rhs);
160*38fd1498Szrj 
161*38fd1498Szrj   target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
162*38fd1498Szrj   reg = expand_normal (rhs);
163*38fd1498Szrj 
164*38fd1498Szrj   gcc_assert (MEM_P (target));
165*38fd1498Szrj   PUT_MODE (target, TYPE_MODE (type));
166*38fd1498Szrj 
167*38fd1498Szrj   create_fixed_operand (&ops[0], target);
168*38fd1498Szrj   create_input_operand (&ops[1], reg, TYPE_MODE (type));
169*38fd1498Szrj   expand_insn (get_multi_vector_move (type, optab), 2, ops);
170*38fd1498Szrj }
171*38fd1498Szrj 
172*38fd1498Szrj static void
expand_ANNOTATE(internal_fn,gcall *)173*38fd1498Szrj expand_ANNOTATE (internal_fn, gcall *)
174*38fd1498Szrj {
175*38fd1498Szrj   gcc_unreachable ();
176*38fd1498Szrj }
177*38fd1498Szrj 
178*38fd1498Szrj /* This should get expanded in omp_device_lower pass.  */
179*38fd1498Szrj 
180*38fd1498Szrj static void
expand_GOMP_USE_SIMT(internal_fn,gcall *)181*38fd1498Szrj expand_GOMP_USE_SIMT (internal_fn, gcall *)
182*38fd1498Szrj {
183*38fd1498Szrj   gcc_unreachable ();
184*38fd1498Szrj }
185*38fd1498Szrj 
186*38fd1498Szrj /* This should get expanded in omp_device_lower pass.  */
187*38fd1498Szrj 
188*38fd1498Szrj static void
expand_GOMP_SIMT_ENTER(internal_fn,gcall *)189*38fd1498Szrj expand_GOMP_SIMT_ENTER (internal_fn, gcall *)
190*38fd1498Szrj {
191*38fd1498Szrj   gcc_unreachable ();
192*38fd1498Szrj }
193*38fd1498Szrj 
194*38fd1498Szrj /* Allocate per-lane storage and begin non-uniform execution region.  */
195*38fd1498Szrj 
196*38fd1498Szrj static void
expand_GOMP_SIMT_ENTER_ALLOC(internal_fn,gcall * stmt)197*38fd1498Szrj expand_GOMP_SIMT_ENTER_ALLOC (internal_fn, gcall *stmt)
198*38fd1498Szrj {
199*38fd1498Szrj   rtx target;
200*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
201*38fd1498Szrj   if (lhs)
202*38fd1498Szrj     target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
203*38fd1498Szrj   else
204*38fd1498Szrj     target = gen_reg_rtx (Pmode);
205*38fd1498Szrj   rtx size = expand_normal (gimple_call_arg (stmt, 0));
206*38fd1498Szrj   rtx align = expand_normal (gimple_call_arg (stmt, 1));
207*38fd1498Szrj   struct expand_operand ops[3];
208*38fd1498Szrj   create_output_operand (&ops[0], target, Pmode);
209*38fd1498Szrj   create_input_operand (&ops[1], size, Pmode);
210*38fd1498Szrj   create_input_operand (&ops[2], align, Pmode);
211*38fd1498Szrj   gcc_assert (targetm.have_omp_simt_enter ());
212*38fd1498Szrj   expand_insn (targetm.code_for_omp_simt_enter, 3, ops);
213*38fd1498Szrj }
214*38fd1498Szrj 
215*38fd1498Szrj /* Deallocate per-lane storage and leave non-uniform execution region.  */
216*38fd1498Szrj 
217*38fd1498Szrj static void
expand_GOMP_SIMT_EXIT(internal_fn,gcall * stmt)218*38fd1498Szrj expand_GOMP_SIMT_EXIT (internal_fn, gcall *stmt)
219*38fd1498Szrj {
220*38fd1498Szrj   gcc_checking_assert (!gimple_call_lhs (stmt));
221*38fd1498Szrj   rtx arg = expand_normal (gimple_call_arg (stmt, 0));
222*38fd1498Szrj   struct expand_operand ops[1];
223*38fd1498Szrj   create_input_operand (&ops[0], arg, Pmode);
224*38fd1498Szrj   gcc_assert (targetm.have_omp_simt_exit ());
225*38fd1498Szrj   expand_insn (targetm.code_for_omp_simt_exit, 1, ops);
226*38fd1498Szrj }
227*38fd1498Szrj 
228*38fd1498Szrj /* Lane index on SIMT targets: thread index in the warp on NVPTX.  On targets
229*38fd1498Szrj    without SIMT execution this should be expanded in omp_device_lower pass.  */
230*38fd1498Szrj 
231*38fd1498Szrj static void
expand_GOMP_SIMT_LANE(internal_fn,gcall * stmt)232*38fd1498Szrj expand_GOMP_SIMT_LANE (internal_fn, gcall *stmt)
233*38fd1498Szrj {
234*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
235*38fd1498Szrj   if (!lhs)
236*38fd1498Szrj     return;
237*38fd1498Szrj 
238*38fd1498Szrj   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
239*38fd1498Szrj   gcc_assert (targetm.have_omp_simt_lane ());
240*38fd1498Szrj   emit_insn (targetm.gen_omp_simt_lane (target));
241*38fd1498Szrj }
242*38fd1498Szrj 
243*38fd1498Szrj /* This should get expanded in omp_device_lower pass.  */
244*38fd1498Szrj 
245*38fd1498Szrj static void
expand_GOMP_SIMT_VF(internal_fn,gcall *)246*38fd1498Szrj expand_GOMP_SIMT_VF (internal_fn, gcall *)
247*38fd1498Szrj {
248*38fd1498Szrj   gcc_unreachable ();
249*38fd1498Szrj }
250*38fd1498Szrj 
251*38fd1498Szrj /* Lane index of the first SIMT lane that supplies a non-zero argument.
252*38fd1498Szrj    This is a SIMT counterpart to GOMP_SIMD_LAST_LANE, used to represent the
253*38fd1498Szrj    lane that executed the last iteration for handling OpenMP lastprivate.  */
254*38fd1498Szrj 
255*38fd1498Szrj static void
expand_GOMP_SIMT_LAST_LANE(internal_fn,gcall * stmt)256*38fd1498Szrj expand_GOMP_SIMT_LAST_LANE (internal_fn, gcall *stmt)
257*38fd1498Szrj {
258*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
259*38fd1498Szrj   if (!lhs)
260*38fd1498Szrj     return;
261*38fd1498Szrj 
262*38fd1498Szrj   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
263*38fd1498Szrj   rtx cond = expand_normal (gimple_call_arg (stmt, 0));
264*38fd1498Szrj   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
265*38fd1498Szrj   struct expand_operand ops[2];
266*38fd1498Szrj   create_output_operand (&ops[0], target, mode);
267*38fd1498Szrj   create_input_operand (&ops[1], cond, mode);
268*38fd1498Szrj   gcc_assert (targetm.have_omp_simt_last_lane ());
269*38fd1498Szrj   expand_insn (targetm.code_for_omp_simt_last_lane, 2, ops);
270*38fd1498Szrj }
271*38fd1498Szrj 
272*38fd1498Szrj /* Non-transparent predicate used in SIMT lowering of OpenMP "ordered".  */
273*38fd1498Szrj 
274*38fd1498Szrj static void
expand_GOMP_SIMT_ORDERED_PRED(internal_fn,gcall * stmt)275*38fd1498Szrj expand_GOMP_SIMT_ORDERED_PRED (internal_fn, gcall *stmt)
276*38fd1498Szrj {
277*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
278*38fd1498Szrj   if (!lhs)
279*38fd1498Szrj     return;
280*38fd1498Szrj 
281*38fd1498Szrj   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
282*38fd1498Szrj   rtx ctr = expand_normal (gimple_call_arg (stmt, 0));
283*38fd1498Szrj   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
284*38fd1498Szrj   struct expand_operand ops[2];
285*38fd1498Szrj   create_output_operand (&ops[0], target, mode);
286*38fd1498Szrj   create_input_operand (&ops[1], ctr, mode);
287*38fd1498Szrj   gcc_assert (targetm.have_omp_simt_ordered ());
288*38fd1498Szrj   expand_insn (targetm.code_for_omp_simt_ordered, 2, ops);
289*38fd1498Szrj }
290*38fd1498Szrj 
291*38fd1498Szrj /* "Or" boolean reduction across SIMT lanes: return non-zero in all lanes if
292*38fd1498Szrj    any lane supplies a non-zero argument.  */
293*38fd1498Szrj 
294*38fd1498Szrj static void
expand_GOMP_SIMT_VOTE_ANY(internal_fn,gcall * stmt)295*38fd1498Szrj expand_GOMP_SIMT_VOTE_ANY (internal_fn, gcall *stmt)
296*38fd1498Szrj {
297*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
298*38fd1498Szrj   if (!lhs)
299*38fd1498Szrj     return;
300*38fd1498Szrj 
301*38fd1498Szrj   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
302*38fd1498Szrj   rtx cond = expand_normal (gimple_call_arg (stmt, 0));
303*38fd1498Szrj   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
304*38fd1498Szrj   struct expand_operand ops[2];
305*38fd1498Szrj   create_output_operand (&ops[0], target, mode);
306*38fd1498Szrj   create_input_operand (&ops[1], cond, mode);
307*38fd1498Szrj   gcc_assert (targetm.have_omp_simt_vote_any ());
308*38fd1498Szrj   expand_insn (targetm.code_for_omp_simt_vote_any, 2, ops);
309*38fd1498Szrj }
310*38fd1498Szrj 
311*38fd1498Szrj /* Exchange between SIMT lanes with a "butterfly" pattern: source lane index
312*38fd1498Szrj    is destination lane index XOR given offset.  */
313*38fd1498Szrj 
314*38fd1498Szrj static void
expand_GOMP_SIMT_XCHG_BFLY(internal_fn,gcall * stmt)315*38fd1498Szrj expand_GOMP_SIMT_XCHG_BFLY (internal_fn, gcall *stmt)
316*38fd1498Szrj {
317*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
318*38fd1498Szrj   if (!lhs)
319*38fd1498Szrj     return;
320*38fd1498Szrj 
321*38fd1498Szrj   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
322*38fd1498Szrj   rtx src = expand_normal (gimple_call_arg (stmt, 0));
323*38fd1498Szrj   rtx idx = expand_normal (gimple_call_arg (stmt, 1));
324*38fd1498Szrj   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
325*38fd1498Szrj   struct expand_operand ops[3];
326*38fd1498Szrj   create_output_operand (&ops[0], target, mode);
327*38fd1498Szrj   create_input_operand (&ops[1], src, mode);
328*38fd1498Szrj   create_input_operand (&ops[2], idx, SImode);
329*38fd1498Szrj   gcc_assert (targetm.have_omp_simt_xchg_bfly ());
330*38fd1498Szrj   expand_insn (targetm.code_for_omp_simt_xchg_bfly, 3, ops);
331*38fd1498Szrj }
332*38fd1498Szrj 
333*38fd1498Szrj /* Exchange between SIMT lanes according to given source lane index.  */
334*38fd1498Szrj 
335*38fd1498Szrj static void
expand_GOMP_SIMT_XCHG_IDX(internal_fn,gcall * stmt)336*38fd1498Szrj expand_GOMP_SIMT_XCHG_IDX (internal_fn, gcall *stmt)
337*38fd1498Szrj {
338*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
339*38fd1498Szrj   if (!lhs)
340*38fd1498Szrj     return;
341*38fd1498Szrj 
342*38fd1498Szrj   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
343*38fd1498Szrj   rtx src = expand_normal (gimple_call_arg (stmt, 0));
344*38fd1498Szrj   rtx idx = expand_normal (gimple_call_arg (stmt, 1));
345*38fd1498Szrj   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
346*38fd1498Szrj   struct expand_operand ops[3];
347*38fd1498Szrj   create_output_operand (&ops[0], target, mode);
348*38fd1498Szrj   create_input_operand (&ops[1], src, mode);
349*38fd1498Szrj   create_input_operand (&ops[2], idx, SImode);
350*38fd1498Szrj   gcc_assert (targetm.have_omp_simt_xchg_idx ());
351*38fd1498Szrj   expand_insn (targetm.code_for_omp_simt_xchg_idx, 3, ops);
352*38fd1498Szrj }
353*38fd1498Szrj 
354*38fd1498Szrj /* This should get expanded in adjust_simduid_builtins.  */
355*38fd1498Szrj 
356*38fd1498Szrj static void
expand_GOMP_SIMD_LANE(internal_fn,gcall *)357*38fd1498Szrj expand_GOMP_SIMD_LANE (internal_fn, gcall *)
358*38fd1498Szrj {
359*38fd1498Szrj   gcc_unreachable ();
360*38fd1498Szrj }
361*38fd1498Szrj 
362*38fd1498Szrj /* This should get expanded in adjust_simduid_builtins.  */
363*38fd1498Szrj 
364*38fd1498Szrj static void
expand_GOMP_SIMD_VF(internal_fn,gcall *)365*38fd1498Szrj expand_GOMP_SIMD_VF (internal_fn, gcall *)
366*38fd1498Szrj {
367*38fd1498Szrj   gcc_unreachable ();
368*38fd1498Szrj }
369*38fd1498Szrj 
370*38fd1498Szrj /* This should get expanded in adjust_simduid_builtins.  */
371*38fd1498Szrj 
372*38fd1498Szrj static void
expand_GOMP_SIMD_LAST_LANE(internal_fn,gcall *)373*38fd1498Szrj expand_GOMP_SIMD_LAST_LANE (internal_fn, gcall *)
374*38fd1498Szrj {
375*38fd1498Szrj   gcc_unreachable ();
376*38fd1498Szrj }
377*38fd1498Szrj 
378*38fd1498Szrj /* This should get expanded in adjust_simduid_builtins.  */
379*38fd1498Szrj 
380*38fd1498Szrj static void
expand_GOMP_SIMD_ORDERED_START(internal_fn,gcall *)381*38fd1498Szrj expand_GOMP_SIMD_ORDERED_START (internal_fn, gcall *)
382*38fd1498Szrj {
383*38fd1498Szrj   gcc_unreachable ();
384*38fd1498Szrj }
385*38fd1498Szrj 
386*38fd1498Szrj /* This should get expanded in adjust_simduid_builtins.  */
387*38fd1498Szrj 
388*38fd1498Szrj static void
expand_GOMP_SIMD_ORDERED_END(internal_fn,gcall *)389*38fd1498Szrj expand_GOMP_SIMD_ORDERED_END (internal_fn, gcall *)
390*38fd1498Szrj {
391*38fd1498Szrj   gcc_unreachable ();
392*38fd1498Szrj }
393*38fd1498Szrj 
394*38fd1498Szrj /* This should get expanded in the sanopt pass.  */
395*38fd1498Szrj 
396*38fd1498Szrj static void
expand_UBSAN_NULL(internal_fn,gcall *)397*38fd1498Szrj expand_UBSAN_NULL (internal_fn, gcall *)
398*38fd1498Szrj {
399*38fd1498Szrj   gcc_unreachable ();
400*38fd1498Szrj }
401*38fd1498Szrj 
402*38fd1498Szrj /* This should get expanded in the sanopt pass.  */
403*38fd1498Szrj 
404*38fd1498Szrj static void
expand_UBSAN_BOUNDS(internal_fn,gcall *)405*38fd1498Szrj expand_UBSAN_BOUNDS (internal_fn, gcall *)
406*38fd1498Szrj {
407*38fd1498Szrj   gcc_unreachable ();
408*38fd1498Szrj }
409*38fd1498Szrj 
410*38fd1498Szrj /* This should get expanded in the sanopt pass.  */
411*38fd1498Szrj 
412*38fd1498Szrj static void
expand_UBSAN_VPTR(internal_fn,gcall *)413*38fd1498Szrj expand_UBSAN_VPTR (internal_fn, gcall *)
414*38fd1498Szrj {
415*38fd1498Szrj   gcc_unreachable ();
416*38fd1498Szrj }
417*38fd1498Szrj 
418*38fd1498Szrj /* This should get expanded in the sanopt pass.  */
419*38fd1498Szrj 
420*38fd1498Szrj static void
expand_UBSAN_PTR(internal_fn,gcall *)421*38fd1498Szrj expand_UBSAN_PTR (internal_fn, gcall *)
422*38fd1498Szrj {
423*38fd1498Szrj   gcc_unreachable ();
424*38fd1498Szrj }
425*38fd1498Szrj 
426*38fd1498Szrj /* This should get expanded in the sanopt pass.  */
427*38fd1498Szrj 
428*38fd1498Szrj static void
expand_UBSAN_OBJECT_SIZE(internal_fn,gcall *)429*38fd1498Szrj expand_UBSAN_OBJECT_SIZE (internal_fn, gcall *)
430*38fd1498Szrj {
431*38fd1498Szrj   gcc_unreachable ();
432*38fd1498Szrj }
433*38fd1498Szrj 
434*38fd1498Szrj /* This should get expanded in the sanopt pass.  */
435*38fd1498Szrj 
436*38fd1498Szrj static void
expand_ASAN_CHECK(internal_fn,gcall *)437*38fd1498Szrj expand_ASAN_CHECK (internal_fn, gcall *)
438*38fd1498Szrj {
439*38fd1498Szrj   gcc_unreachable ();
440*38fd1498Szrj }
441*38fd1498Szrj 
442*38fd1498Szrj /* This should get expanded in the sanopt pass.  */
443*38fd1498Szrj 
444*38fd1498Szrj static void
expand_ASAN_MARK(internal_fn,gcall *)445*38fd1498Szrj expand_ASAN_MARK (internal_fn, gcall *)
446*38fd1498Szrj {
447*38fd1498Szrj   gcc_unreachable ();
448*38fd1498Szrj }
449*38fd1498Szrj 
450*38fd1498Szrj /* This should get expanded in the sanopt pass.  */
451*38fd1498Szrj 
452*38fd1498Szrj static void
expand_ASAN_POISON(internal_fn,gcall *)453*38fd1498Szrj expand_ASAN_POISON (internal_fn, gcall *)
454*38fd1498Szrj {
455*38fd1498Szrj   gcc_unreachable ();
456*38fd1498Szrj }
457*38fd1498Szrj 
458*38fd1498Szrj /* This should get expanded in the sanopt pass.  */
459*38fd1498Szrj 
460*38fd1498Szrj static void
expand_ASAN_POISON_USE(internal_fn,gcall *)461*38fd1498Szrj expand_ASAN_POISON_USE (internal_fn, gcall *)
462*38fd1498Szrj {
463*38fd1498Szrj   gcc_unreachable ();
464*38fd1498Szrj }
465*38fd1498Szrj 
466*38fd1498Szrj /* This should get expanded in the tsan pass.  */
467*38fd1498Szrj 
468*38fd1498Szrj static void
expand_TSAN_FUNC_EXIT(internal_fn,gcall *)469*38fd1498Szrj expand_TSAN_FUNC_EXIT (internal_fn, gcall *)
470*38fd1498Szrj {
471*38fd1498Szrj   gcc_unreachable ();
472*38fd1498Szrj }
473*38fd1498Szrj 
474*38fd1498Szrj /* This should get expanded in the lower pass.  */
475*38fd1498Szrj 
476*38fd1498Szrj static void
expand_FALLTHROUGH(internal_fn,gcall * call)477*38fd1498Szrj expand_FALLTHROUGH (internal_fn, gcall *call)
478*38fd1498Szrj {
479*38fd1498Szrj   error_at (gimple_location (call),
480*38fd1498Szrj 	    "invalid use of attribute %<fallthrough%>");
481*38fd1498Szrj }
482*38fd1498Szrj 
483*38fd1498Szrj /* Return minimum precision needed to represent all values
484*38fd1498Szrj    of ARG in SIGNed integral type.  */
485*38fd1498Szrj 
486*38fd1498Szrj static int
get_min_precision(tree arg,signop sign)487*38fd1498Szrj get_min_precision (tree arg, signop sign)
488*38fd1498Szrj {
489*38fd1498Szrj   int prec = TYPE_PRECISION (TREE_TYPE (arg));
490*38fd1498Szrj   int cnt = 0;
491*38fd1498Szrj   signop orig_sign = sign;
492*38fd1498Szrj   if (TREE_CODE (arg) == INTEGER_CST)
493*38fd1498Szrj     {
494*38fd1498Szrj       int p;
495*38fd1498Szrj       if (TYPE_SIGN (TREE_TYPE (arg)) != sign)
496*38fd1498Szrj 	{
497*38fd1498Szrj 	  widest_int w = wi::to_widest (arg);
498*38fd1498Szrj 	  w = wi::ext (w, prec, sign);
499*38fd1498Szrj 	  p = wi::min_precision (w, sign);
500*38fd1498Szrj 	}
501*38fd1498Szrj       else
502*38fd1498Szrj 	p = wi::min_precision (wi::to_wide (arg), sign);
503*38fd1498Szrj       return MIN (p, prec);
504*38fd1498Szrj     }
505*38fd1498Szrj   while (CONVERT_EXPR_P (arg)
506*38fd1498Szrj 	 && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
507*38fd1498Szrj 	 && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
508*38fd1498Szrj     {
509*38fd1498Szrj       arg = TREE_OPERAND (arg, 0);
510*38fd1498Szrj       if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
511*38fd1498Szrj 	{
512*38fd1498Szrj 	  if (TYPE_UNSIGNED (TREE_TYPE (arg)))
513*38fd1498Szrj 	    sign = UNSIGNED;
514*38fd1498Szrj 	  else if (sign == UNSIGNED && get_range_pos_neg (arg) != 1)
515*38fd1498Szrj 	    return prec + (orig_sign != sign);
516*38fd1498Szrj 	  prec = TYPE_PRECISION (TREE_TYPE (arg));
517*38fd1498Szrj 	}
518*38fd1498Szrj       if (++cnt > 30)
519*38fd1498Szrj 	return prec + (orig_sign != sign);
520*38fd1498Szrj     }
521*38fd1498Szrj   if (TREE_CODE (arg) != SSA_NAME)
522*38fd1498Szrj     return prec + (orig_sign != sign);
523*38fd1498Szrj   wide_int arg_min, arg_max;
524*38fd1498Szrj   while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
525*38fd1498Szrj     {
526*38fd1498Szrj       gimple *g = SSA_NAME_DEF_STMT (arg);
527*38fd1498Szrj       if (is_gimple_assign (g)
528*38fd1498Szrj 	  && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
529*38fd1498Szrj 	{
530*38fd1498Szrj 	  tree t = gimple_assign_rhs1 (g);
531*38fd1498Szrj 	  if (INTEGRAL_TYPE_P (TREE_TYPE (t))
532*38fd1498Szrj 	      && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
533*38fd1498Szrj 	    {
534*38fd1498Szrj 	      arg = t;
535*38fd1498Szrj 	      if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
536*38fd1498Szrj 		{
537*38fd1498Szrj 		  if (TYPE_UNSIGNED (TREE_TYPE (arg)))
538*38fd1498Szrj 		    sign = UNSIGNED;
539*38fd1498Szrj 		  else if (sign == UNSIGNED && get_range_pos_neg (arg) != 1)
540*38fd1498Szrj 		    return prec + (orig_sign != sign);
541*38fd1498Szrj 		  prec = TYPE_PRECISION (TREE_TYPE (arg));
542*38fd1498Szrj 		}
543*38fd1498Szrj 	      if (++cnt > 30)
544*38fd1498Szrj 		return prec + (orig_sign != sign);
545*38fd1498Szrj 	      continue;
546*38fd1498Szrj 	    }
547*38fd1498Szrj 	}
548*38fd1498Szrj       return prec + (orig_sign != sign);
549*38fd1498Szrj     }
550*38fd1498Szrj   if (sign == TYPE_SIGN (TREE_TYPE (arg)))
551*38fd1498Szrj     {
552*38fd1498Szrj       int p1 = wi::min_precision (arg_min, sign);
553*38fd1498Szrj       int p2 = wi::min_precision (arg_max, sign);
554*38fd1498Szrj       p1 = MAX (p1, p2);
555*38fd1498Szrj       prec = MIN (prec, p1);
556*38fd1498Szrj     }
557*38fd1498Szrj   else if (sign == UNSIGNED && !wi::neg_p (arg_min, SIGNED))
558*38fd1498Szrj     {
559*38fd1498Szrj       int p = wi::min_precision (arg_max, UNSIGNED);
560*38fd1498Szrj       prec = MIN (prec, p);
561*38fd1498Szrj     }
562*38fd1498Szrj   return prec + (orig_sign != sign);
563*38fd1498Szrj }
564*38fd1498Szrj 
565*38fd1498Szrj /* Helper for expand_*_overflow.  Set the __imag__ part to true
566*38fd1498Szrj    (1 except for signed:1 type, in which case store -1).  */
567*38fd1498Szrj 
568*38fd1498Szrj static void
expand_arith_set_overflow(tree lhs,rtx target)569*38fd1498Szrj expand_arith_set_overflow (tree lhs, rtx target)
570*38fd1498Szrj {
571*38fd1498Szrj   if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs))) == 1
572*38fd1498Szrj       && !TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs))))
573*38fd1498Szrj     write_complex_part (target, constm1_rtx, true);
574*38fd1498Szrj   else
575*38fd1498Szrj     write_complex_part (target, const1_rtx, true);
576*38fd1498Szrj }
577*38fd1498Szrj 
578*38fd1498Szrj /* Helper for expand_*_overflow.  Store RES into the __real__ part
579*38fd1498Szrj    of TARGET.  If RES has larger MODE than __real__ part of TARGET,
580*38fd1498Szrj    set the __imag__ part to 1 if RES doesn't fit into it.  Similarly
581*38fd1498Szrj    if LHS has smaller precision than its mode.  */
582*38fd1498Szrj 
583*38fd1498Szrj static void
expand_arith_overflow_result_store(tree lhs,rtx target,scalar_int_mode mode,rtx res)584*38fd1498Szrj expand_arith_overflow_result_store (tree lhs, rtx target,
585*38fd1498Szrj 				    scalar_int_mode mode, rtx res)
586*38fd1498Szrj {
587*38fd1498Szrj   scalar_int_mode tgtmode
588*38fd1498Szrj     = as_a <scalar_int_mode> (GET_MODE_INNER (GET_MODE (target)));
589*38fd1498Szrj   rtx lres = res;
590*38fd1498Szrj   if (tgtmode != mode)
591*38fd1498Szrj     {
592*38fd1498Szrj       rtx_code_label *done_label = gen_label_rtx ();
593*38fd1498Szrj       int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
594*38fd1498Szrj       lres = convert_modes (tgtmode, mode, res, uns);
595*38fd1498Szrj       gcc_assert (GET_MODE_PRECISION (tgtmode) < GET_MODE_PRECISION (mode));
596*38fd1498Szrj       do_compare_rtx_and_jump (res, convert_modes (mode, tgtmode, lres, uns),
597*38fd1498Szrj 			       EQ, true, mode, NULL_RTX, NULL, done_label,
598*38fd1498Szrj 			       profile_probability::very_likely ());
599*38fd1498Szrj       expand_arith_set_overflow (lhs, target);
600*38fd1498Szrj       emit_label (done_label);
601*38fd1498Szrj     }
602*38fd1498Szrj   int prec = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs)));
603*38fd1498Szrj   int tgtprec = GET_MODE_PRECISION (tgtmode);
604*38fd1498Szrj   if (prec < tgtprec)
605*38fd1498Szrj     {
606*38fd1498Szrj       rtx_code_label *done_label = gen_label_rtx ();
607*38fd1498Szrj       int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
608*38fd1498Szrj       res = lres;
609*38fd1498Szrj       if (uns)
610*38fd1498Szrj 	{
611*38fd1498Szrj 	  rtx mask
612*38fd1498Szrj 	    = immed_wide_int_const (wi::shifted_mask (0, prec, false, tgtprec),
613*38fd1498Szrj 				    tgtmode);
614*38fd1498Szrj 	  lres = expand_simple_binop (tgtmode, AND, res, mask, NULL_RTX,
615*38fd1498Szrj 				      true, OPTAB_LIB_WIDEN);
616*38fd1498Szrj 	}
617*38fd1498Szrj       else
618*38fd1498Szrj 	{
619*38fd1498Szrj 	  lres = expand_shift (LSHIFT_EXPR, tgtmode, res, tgtprec - prec,
620*38fd1498Szrj 			       NULL_RTX, 1);
621*38fd1498Szrj 	  lres = expand_shift (RSHIFT_EXPR, tgtmode, lres, tgtprec - prec,
622*38fd1498Szrj 			       NULL_RTX, 0);
623*38fd1498Szrj 	}
624*38fd1498Szrj       do_compare_rtx_and_jump (res, lres,
625*38fd1498Szrj 			       EQ, true, tgtmode, NULL_RTX, NULL, done_label,
626*38fd1498Szrj 			       profile_probability::very_likely ());
627*38fd1498Szrj       expand_arith_set_overflow (lhs, target);
628*38fd1498Szrj       emit_label (done_label);
629*38fd1498Szrj     }
630*38fd1498Szrj   write_complex_part (target, lres, false);
631*38fd1498Szrj }
632*38fd1498Szrj 
633*38fd1498Szrj /* Helper for expand_*_overflow.  Store RES into TARGET.  */
634*38fd1498Szrj 
635*38fd1498Szrj static void
expand_ubsan_result_store(rtx target,rtx res)636*38fd1498Szrj expand_ubsan_result_store (rtx target, rtx res)
637*38fd1498Szrj {
638*38fd1498Szrj   if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
639*38fd1498Szrj     /* If this is a scalar in a register that is stored in a wider mode
640*38fd1498Szrj        than the declared mode, compute the result into its declared mode
641*38fd1498Szrj        and then convert to the wider mode.  Our value is the computed
642*38fd1498Szrj        expression.  */
643*38fd1498Szrj     convert_move (SUBREG_REG (target), res, SUBREG_PROMOTED_SIGN (target));
644*38fd1498Szrj   else
645*38fd1498Szrj     emit_move_insn (target, res);
646*38fd1498Szrj }
647*38fd1498Szrj 
648*38fd1498Szrj /* Add sub/add overflow checking to the statement STMT.
649*38fd1498Szrj    CODE says whether the operation is +, or -.  */
650*38fd1498Szrj 
651*38fd1498Szrj static void
expand_addsub_overflow(location_t loc,tree_code code,tree lhs,tree arg0,tree arg1,bool unsr_p,bool uns0_p,bool uns1_p,bool is_ubsan,tree * datap)652*38fd1498Szrj expand_addsub_overflow (location_t loc, tree_code code, tree lhs,
653*38fd1498Szrj 			tree arg0, tree arg1, bool unsr_p, bool uns0_p,
654*38fd1498Szrj 			bool uns1_p, bool is_ubsan, tree *datap)
655*38fd1498Szrj {
656*38fd1498Szrj   rtx res, target = NULL_RTX;
657*38fd1498Szrj   tree fn;
658*38fd1498Szrj   rtx_code_label *done_label = gen_label_rtx ();
659*38fd1498Szrj   rtx_code_label *do_error = gen_label_rtx ();
660*38fd1498Szrj   do_pending_stack_adjust ();
661*38fd1498Szrj   rtx op0 = expand_normal (arg0);
662*38fd1498Szrj   rtx op1 = expand_normal (arg1);
663*38fd1498Szrj   scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg0));
664*38fd1498Szrj   int prec = GET_MODE_PRECISION (mode);
665*38fd1498Szrj   rtx sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
666*38fd1498Szrj   bool do_xor = false;
667*38fd1498Szrj 
668*38fd1498Szrj   if (is_ubsan)
669*38fd1498Szrj     gcc_assert (!unsr_p && !uns0_p && !uns1_p);
670*38fd1498Szrj 
671*38fd1498Szrj   if (lhs)
672*38fd1498Szrj     {
673*38fd1498Szrj       target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
674*38fd1498Szrj       if (!is_ubsan)
675*38fd1498Szrj 	write_complex_part (target, const0_rtx, true);
676*38fd1498Szrj     }
677*38fd1498Szrj 
678*38fd1498Szrj   /* We assume both operands and result have the same precision
679*38fd1498Szrj      here (GET_MODE_BITSIZE (mode)), S stands for signed type
680*38fd1498Szrj      with that precision, U for unsigned type with that precision,
681*38fd1498Szrj      sgn for unsigned most significant bit in that precision.
682*38fd1498Szrj      s1 is signed first operand, u1 is unsigned first operand,
683*38fd1498Szrj      s2 is signed second operand, u2 is unsigned second operand,
684*38fd1498Szrj      sr is signed result, ur is unsigned result and the following
685*38fd1498Szrj      rules say how to compute result (which is always result of
686*38fd1498Szrj      the operands as if both were unsigned, cast to the right
687*38fd1498Szrj      signedness) and how to compute whether operation overflowed.
688*38fd1498Szrj 
689*38fd1498Szrj      s1 + s2 -> sr
690*38fd1498Szrj 	res = (S) ((U) s1 + (U) s2)
691*38fd1498Szrj 	ovf = s2 < 0 ? res > s1 : res < s1 (or jump on overflow)
692*38fd1498Szrj      s1 - s2 -> sr
693*38fd1498Szrj 	res = (S) ((U) s1 - (U) s2)
694*38fd1498Szrj 	ovf = s2 < 0 ? res < s1 : res > s2 (or jump on overflow)
695*38fd1498Szrj      u1 + u2 -> ur
696*38fd1498Szrj 	res = u1 + u2
697*38fd1498Szrj 	ovf = res < u1 (or jump on carry, but RTL opts will handle it)
698*38fd1498Szrj      u1 - u2 -> ur
699*38fd1498Szrj 	res = u1 - u2
700*38fd1498Szrj 	ovf = res > u1 (or jump on carry, but RTL opts will handle it)
701*38fd1498Szrj      s1 + u2 -> sr
702*38fd1498Szrj 	res = (S) ((U) s1 + u2)
703*38fd1498Szrj 	ovf = ((U) res ^ sgn) < u2
704*38fd1498Szrj      s1 + u2 -> ur
705*38fd1498Szrj 	t1 = (S) (u2 ^ sgn)
706*38fd1498Szrj 	t2 = s1 + t1
707*38fd1498Szrj 	res = (U) t2 ^ sgn
708*38fd1498Szrj 	ovf = t1 < 0 ? t2 > s1 : t2 < s1 (or jump on overflow)
709*38fd1498Szrj      s1 - u2 -> sr
710*38fd1498Szrj 	res = (S) ((U) s1 - u2)
711*38fd1498Szrj 	ovf = u2 > ((U) s1 ^ sgn)
712*38fd1498Szrj      s1 - u2 -> ur
713*38fd1498Szrj 	res = (U) s1 - u2
714*38fd1498Szrj 	ovf = s1 < 0 || u2 > (U) s1
715*38fd1498Szrj      u1 - s2 -> sr
716*38fd1498Szrj 	res = u1 - (U) s2
717*38fd1498Szrj  	ovf = u1 >= ((U) s2 ^ sgn)
718*38fd1498Szrj      u1 - s2 -> ur
719*38fd1498Szrj 	t1 = u1 ^ sgn
720*38fd1498Szrj 	t2 = t1 - (U) s2
721*38fd1498Szrj 	res = t2 ^ sgn
722*38fd1498Szrj 	ovf = s2 < 0 ? (S) t2 < (S) t1 : (S) t2 > (S) t1 (or jump on overflow)
723*38fd1498Szrj      s1 + s2 -> ur
724*38fd1498Szrj 	res = (U) s1 + (U) s2
725*38fd1498Szrj 	ovf = s2 < 0 ? (s1 | (S) res) < 0) : (s1 & (S) res) < 0)
726*38fd1498Szrj      u1 + u2 -> sr
727*38fd1498Szrj 	res = (S) (u1 + u2)
728*38fd1498Szrj 	ovf = (U) res < u2 || res < 0
729*38fd1498Szrj      u1 - u2 -> sr
730*38fd1498Szrj 	res = (S) (u1 - u2)
731*38fd1498Szrj 	ovf = u1 >= u2 ? res < 0 : res >= 0
732*38fd1498Szrj      s1 - s2 -> ur
733*38fd1498Szrj 	res = (U) s1 - (U) s2
734*38fd1498Szrj 	ovf = s2 >= 0 ? ((s1 | (S) res) < 0) : ((s1 & (S) res) < 0)  */
735*38fd1498Szrj 
736*38fd1498Szrj   if (code == PLUS_EXPR && uns0_p && !uns1_p)
737*38fd1498Szrj     {
738*38fd1498Szrj       /* PLUS_EXPR is commutative, if operand signedness differs,
739*38fd1498Szrj 	 canonicalize to the first operand being signed and second
740*38fd1498Szrj 	 unsigned to simplify following code.  */
741*38fd1498Szrj       std::swap (op0, op1);
742*38fd1498Szrj       std::swap (arg0, arg1);
743*38fd1498Szrj       uns0_p = false;
744*38fd1498Szrj       uns1_p = true;
745*38fd1498Szrj     }
746*38fd1498Szrj 
747*38fd1498Szrj   /* u1 +- u2 -> ur  */
748*38fd1498Szrj   if (uns0_p && uns1_p && unsr_p)
749*38fd1498Szrj     {
750*38fd1498Szrj       insn_code icode = optab_handler (code == PLUS_EXPR ? uaddv4_optab
751*38fd1498Szrj                                        : usubv4_optab, mode);
752*38fd1498Szrj       if (icode != CODE_FOR_nothing)
753*38fd1498Szrj 	{
754*38fd1498Szrj 	  struct expand_operand ops[4];
755*38fd1498Szrj 	  rtx_insn *last = get_last_insn ();
756*38fd1498Szrj 
757*38fd1498Szrj 	  res = gen_reg_rtx (mode);
758*38fd1498Szrj 	  create_output_operand (&ops[0], res, mode);
759*38fd1498Szrj 	  create_input_operand (&ops[1], op0, mode);
760*38fd1498Szrj 	  create_input_operand (&ops[2], op1, mode);
761*38fd1498Szrj 	  create_fixed_operand (&ops[3], do_error);
762*38fd1498Szrj 	  if (maybe_expand_insn (icode, 4, ops))
763*38fd1498Szrj 	    {
764*38fd1498Szrj 	      last = get_last_insn ();
765*38fd1498Szrj 	      if (profile_status_for_fn (cfun) != PROFILE_ABSENT
766*38fd1498Szrj 		  && JUMP_P (last)
767*38fd1498Szrj 		  && any_condjump_p (last)
768*38fd1498Szrj 		  && !find_reg_note (last, REG_BR_PROB, 0))
769*38fd1498Szrj 		add_reg_br_prob_note (last,
770*38fd1498Szrj 				      profile_probability::very_unlikely ());
771*38fd1498Szrj 	      emit_jump (done_label);
772*38fd1498Szrj 	      goto do_error_label;
773*38fd1498Szrj 	    }
774*38fd1498Szrj 
775*38fd1498Szrj 	  delete_insns_since (last);
776*38fd1498Szrj 	}
777*38fd1498Szrj 
778*38fd1498Szrj       /* Compute the operation.  On RTL level, the addition is always
779*38fd1498Szrj 	 unsigned.  */
780*38fd1498Szrj       res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
781*38fd1498Szrj 			  op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
782*38fd1498Szrj       rtx tem = op0;
783*38fd1498Szrj       /* For PLUS_EXPR, the operation is commutative, so we can pick
784*38fd1498Szrj 	 operand to compare against.  For prec <= BITS_PER_WORD, I think
785*38fd1498Szrj 	 preferring REG operand is better over CONST_INT, because
786*38fd1498Szrj 	 the CONST_INT might enlarge the instruction or CSE would need
787*38fd1498Szrj 	 to figure out we'd already loaded it into a register before.
788*38fd1498Szrj 	 For prec > BITS_PER_WORD, I think CONST_INT might be more beneficial,
789*38fd1498Szrj 	 as then the multi-word comparison can be perhaps simplified.  */
790*38fd1498Szrj       if (code == PLUS_EXPR
791*38fd1498Szrj 	  && (prec <= BITS_PER_WORD
792*38fd1498Szrj 	      ? (CONST_SCALAR_INT_P (op0) && REG_P (op1))
793*38fd1498Szrj 	      : CONST_SCALAR_INT_P (op1)))
794*38fd1498Szrj 	tem = op1;
795*38fd1498Szrj       do_compare_rtx_and_jump (res, tem, code == PLUS_EXPR ? GEU : LEU,
796*38fd1498Szrj 			       true, mode, NULL_RTX, NULL, done_label,
797*38fd1498Szrj 			       profile_probability::very_likely ());
798*38fd1498Szrj       goto do_error_label;
799*38fd1498Szrj     }
800*38fd1498Szrj 
801*38fd1498Szrj   /* s1 +- u2 -> sr  */
802*38fd1498Szrj   if (!uns0_p && uns1_p && !unsr_p)
803*38fd1498Szrj     {
804*38fd1498Szrj       /* Compute the operation.  On RTL level, the addition is always
805*38fd1498Szrj 	 unsigned.  */
806*38fd1498Szrj       res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
807*38fd1498Szrj 			  op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
808*38fd1498Szrj       rtx tem = expand_binop (mode, add_optab,
809*38fd1498Szrj 			      code == PLUS_EXPR ? res : op0, sgn,
810*38fd1498Szrj 			      NULL_RTX, false, OPTAB_LIB_WIDEN);
811*38fd1498Szrj       do_compare_rtx_and_jump (tem, op1, GEU, true, mode, NULL_RTX, NULL,
812*38fd1498Szrj 			       done_label, profile_probability::very_likely ());
813*38fd1498Szrj       goto do_error_label;
814*38fd1498Szrj     }
815*38fd1498Szrj 
816*38fd1498Szrj   /* s1 + u2 -> ur  */
817*38fd1498Szrj   if (code == PLUS_EXPR && !uns0_p && uns1_p && unsr_p)
818*38fd1498Szrj     {
819*38fd1498Szrj       op1 = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
820*38fd1498Szrj 			  OPTAB_LIB_WIDEN);
821*38fd1498Szrj       /* As we've changed op1, we have to avoid using the value range
822*38fd1498Szrj 	 for the original argument.  */
823*38fd1498Szrj       arg1 = error_mark_node;
824*38fd1498Szrj       do_xor = true;
825*38fd1498Szrj       goto do_signed;
826*38fd1498Szrj     }
827*38fd1498Szrj 
828*38fd1498Szrj   /* u1 - s2 -> ur  */
829*38fd1498Szrj   if (code == MINUS_EXPR && uns0_p && !uns1_p && unsr_p)
830*38fd1498Szrj     {
831*38fd1498Szrj       op0 = expand_binop (mode, add_optab, op0, sgn, NULL_RTX, false,
832*38fd1498Szrj 			  OPTAB_LIB_WIDEN);
833*38fd1498Szrj       /* As we've changed op0, we have to avoid using the value range
834*38fd1498Szrj 	 for the original argument.  */
835*38fd1498Szrj       arg0 = error_mark_node;
836*38fd1498Szrj       do_xor = true;
837*38fd1498Szrj       goto do_signed;
838*38fd1498Szrj     }
839*38fd1498Szrj 
840*38fd1498Szrj   /* s1 - u2 -> ur  */
841*38fd1498Szrj   if (code == MINUS_EXPR && !uns0_p && uns1_p && unsr_p)
842*38fd1498Szrj     {
843*38fd1498Szrj       /* Compute the operation.  On RTL level, the addition is always
844*38fd1498Szrj 	 unsigned.  */
845*38fd1498Szrj       res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
846*38fd1498Szrj 			  OPTAB_LIB_WIDEN);
847*38fd1498Szrj       int pos_neg = get_range_pos_neg (arg0);
848*38fd1498Szrj       if (pos_neg == 2)
849*38fd1498Szrj 	/* If ARG0 is known to be always negative, this is always overflow.  */
850*38fd1498Szrj 	emit_jump (do_error);
851*38fd1498Szrj       else if (pos_neg == 3)
852*38fd1498Szrj 	/* If ARG0 is not known to be always positive, check at runtime.  */
853*38fd1498Szrj 	do_compare_rtx_and_jump (op0, const0_rtx, LT, false, mode, NULL_RTX,
854*38fd1498Szrj 				 NULL, do_error, profile_probability::very_unlikely ());
855*38fd1498Szrj       do_compare_rtx_and_jump (op1, op0, LEU, true, mode, NULL_RTX, NULL,
856*38fd1498Szrj 			       done_label, profile_probability::very_likely ());
857*38fd1498Szrj       goto do_error_label;
858*38fd1498Szrj     }
859*38fd1498Szrj 
860*38fd1498Szrj   /* u1 - s2 -> sr  */
861*38fd1498Szrj   if (code == MINUS_EXPR && uns0_p && !uns1_p && !unsr_p)
862*38fd1498Szrj     {
863*38fd1498Szrj       /* Compute the operation.  On RTL level, the addition is always
864*38fd1498Szrj 	 unsigned.  */
865*38fd1498Szrj       res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
866*38fd1498Szrj 			  OPTAB_LIB_WIDEN);
867*38fd1498Szrj       rtx tem = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
868*38fd1498Szrj 			      OPTAB_LIB_WIDEN);
869*38fd1498Szrj       do_compare_rtx_and_jump (op0, tem, LTU, true, mode, NULL_RTX, NULL,
870*38fd1498Szrj 			       done_label, profile_probability::very_likely ());
871*38fd1498Szrj       goto do_error_label;
872*38fd1498Szrj     }
873*38fd1498Szrj 
874*38fd1498Szrj   /* u1 + u2 -> sr  */
875*38fd1498Szrj   if (code == PLUS_EXPR && uns0_p && uns1_p && !unsr_p)
876*38fd1498Szrj     {
877*38fd1498Szrj       /* Compute the operation.  On RTL level, the addition is always
878*38fd1498Szrj 	 unsigned.  */
879*38fd1498Szrj       res = expand_binop (mode, add_optab, op0, op1, NULL_RTX, false,
880*38fd1498Szrj 			  OPTAB_LIB_WIDEN);
881*38fd1498Szrj       do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX,
882*38fd1498Szrj 			       NULL, do_error, profile_probability::very_unlikely ());
883*38fd1498Szrj       rtx tem = op1;
884*38fd1498Szrj       /* The operation is commutative, so we can pick operand to compare
885*38fd1498Szrj 	 against.  For prec <= BITS_PER_WORD, I think preferring REG operand
886*38fd1498Szrj 	 is better over CONST_INT, because the CONST_INT might enlarge the
887*38fd1498Szrj 	 instruction or CSE would need to figure out we'd already loaded it
888*38fd1498Szrj 	 into a register before.  For prec > BITS_PER_WORD, I think CONST_INT
889*38fd1498Szrj 	 might be more beneficial, as then the multi-word comparison can be
890*38fd1498Szrj 	 perhaps simplified.  */
891*38fd1498Szrj       if (prec <= BITS_PER_WORD
892*38fd1498Szrj 	  ? (CONST_SCALAR_INT_P (op1) && REG_P (op0))
893*38fd1498Szrj 	  : CONST_SCALAR_INT_P (op0))
894*38fd1498Szrj 	tem = op0;
895*38fd1498Szrj       do_compare_rtx_and_jump (res, tem, GEU, true, mode, NULL_RTX, NULL,
896*38fd1498Szrj 			       done_label, profile_probability::very_likely ());
897*38fd1498Szrj       goto do_error_label;
898*38fd1498Szrj     }
899*38fd1498Szrj 
900*38fd1498Szrj   /* s1 +- s2 -> ur  */
901*38fd1498Szrj   if (!uns0_p && !uns1_p && unsr_p)
902*38fd1498Szrj     {
903*38fd1498Szrj       /* Compute the operation.  On RTL level, the addition is always
904*38fd1498Szrj 	 unsigned.  */
905*38fd1498Szrj       res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
906*38fd1498Szrj 			  op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
907*38fd1498Szrj       int pos_neg = get_range_pos_neg (arg1);
908*38fd1498Szrj       if (code == PLUS_EXPR)
909*38fd1498Szrj 	{
910*38fd1498Szrj 	  int pos_neg0 = get_range_pos_neg (arg0);
911*38fd1498Szrj 	  if (pos_neg0 != 3 && pos_neg == 3)
912*38fd1498Szrj 	    {
913*38fd1498Szrj 	      std::swap (op0, op1);
914*38fd1498Szrj 	      pos_neg = pos_neg0;
915*38fd1498Szrj 	    }
916*38fd1498Szrj 	}
917*38fd1498Szrj       rtx tem;
918*38fd1498Szrj       if (pos_neg != 3)
919*38fd1498Szrj 	{
920*38fd1498Szrj 	  tem = expand_binop (mode, ((pos_neg == 1) ^ (code == MINUS_EXPR))
921*38fd1498Szrj 				    ? and_optab : ior_optab,
922*38fd1498Szrj 			      op0, res, NULL_RTX, false, OPTAB_LIB_WIDEN);
923*38fd1498Szrj 	  do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL,
924*38fd1498Szrj 				   NULL, done_label, profile_probability::very_likely ());
925*38fd1498Szrj 	}
926*38fd1498Szrj       else
927*38fd1498Szrj 	{
928*38fd1498Szrj 	  rtx_code_label *do_ior_label = gen_label_rtx ();
929*38fd1498Szrj 	  do_compare_rtx_and_jump (op1, const0_rtx,
930*38fd1498Szrj 				   code == MINUS_EXPR ? GE : LT, false, mode,
931*38fd1498Szrj 				   NULL_RTX, NULL, do_ior_label,
932*38fd1498Szrj 				   profile_probability::even ());
933*38fd1498Szrj 	  tem = expand_binop (mode, and_optab, op0, res, NULL_RTX, false,
934*38fd1498Szrj 			      OPTAB_LIB_WIDEN);
935*38fd1498Szrj 	  do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
936*38fd1498Szrj 				   NULL, done_label, profile_probability::very_likely ());
937*38fd1498Szrj 	  emit_jump (do_error);
938*38fd1498Szrj 	  emit_label (do_ior_label);
939*38fd1498Szrj 	  tem = expand_binop (mode, ior_optab, op0, res, NULL_RTX, false,
940*38fd1498Szrj 			      OPTAB_LIB_WIDEN);
941*38fd1498Szrj 	  do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
942*38fd1498Szrj 				   NULL, done_label, profile_probability::very_likely ());
943*38fd1498Szrj 	}
944*38fd1498Szrj       goto do_error_label;
945*38fd1498Szrj     }
946*38fd1498Szrj 
947*38fd1498Szrj   /* u1 - u2 -> sr  */
948*38fd1498Szrj   if (code == MINUS_EXPR && uns0_p && uns1_p && !unsr_p)
949*38fd1498Szrj     {
950*38fd1498Szrj       /* Compute the operation.  On RTL level, the addition is always
951*38fd1498Szrj 	 unsigned.  */
952*38fd1498Szrj       res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
953*38fd1498Szrj 			  OPTAB_LIB_WIDEN);
954*38fd1498Szrj       rtx_code_label *op0_geu_op1 = gen_label_rtx ();
955*38fd1498Szrj       do_compare_rtx_and_jump (op0, op1, GEU, true, mode, NULL_RTX, NULL,
956*38fd1498Szrj 			       op0_geu_op1, profile_probability::even ());
957*38fd1498Szrj       do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX,
958*38fd1498Szrj 			       NULL, done_label, profile_probability::very_likely ());
959*38fd1498Szrj       emit_jump (do_error);
960*38fd1498Szrj       emit_label (op0_geu_op1);
961*38fd1498Szrj       do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
962*38fd1498Szrj 			       NULL, done_label, profile_probability::very_likely ());
963*38fd1498Szrj       goto do_error_label;
964*38fd1498Szrj     }
965*38fd1498Szrj 
966*38fd1498Szrj   gcc_assert (!uns0_p && !uns1_p && !unsr_p);
967*38fd1498Szrj 
968*38fd1498Szrj   /* s1 +- s2 -> sr  */
969*38fd1498Szrj  do_signed:
970*38fd1498Szrj   {
971*38fd1498Szrj     insn_code icode = optab_handler (code == PLUS_EXPR ? addv4_optab
972*38fd1498Szrj 				     : subv4_optab, mode);
973*38fd1498Szrj     if (icode != CODE_FOR_nothing)
974*38fd1498Szrj       {
975*38fd1498Szrj 	struct expand_operand ops[4];
976*38fd1498Szrj 	rtx_insn *last = get_last_insn ();
977*38fd1498Szrj 
978*38fd1498Szrj 	res = gen_reg_rtx (mode);
979*38fd1498Szrj 	create_output_operand (&ops[0], res, mode);
980*38fd1498Szrj 	create_input_operand (&ops[1], op0, mode);
981*38fd1498Szrj 	create_input_operand (&ops[2], op1, mode);
982*38fd1498Szrj 	create_fixed_operand (&ops[3], do_error);
983*38fd1498Szrj 	if (maybe_expand_insn (icode, 4, ops))
984*38fd1498Szrj 	  {
985*38fd1498Szrj 	    last = get_last_insn ();
986*38fd1498Szrj 	    if (profile_status_for_fn (cfun) != PROFILE_ABSENT
987*38fd1498Szrj 		&& JUMP_P (last)
988*38fd1498Szrj 		&& any_condjump_p (last)
989*38fd1498Szrj 		&& !find_reg_note (last, REG_BR_PROB, 0))
990*38fd1498Szrj 	      add_reg_br_prob_note (last,
991*38fd1498Szrj 				    profile_probability::very_unlikely ());
992*38fd1498Szrj 	    emit_jump (done_label);
993*38fd1498Szrj 	    goto do_error_label;
994*38fd1498Szrj 	  }
995*38fd1498Szrj 
996*38fd1498Szrj 	delete_insns_since (last);
997*38fd1498Szrj       }
998*38fd1498Szrj 
999*38fd1498Szrj     /* Compute the operation.  On RTL level, the addition is always
1000*38fd1498Szrj        unsigned.  */
1001*38fd1498Szrj     res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
1002*38fd1498Szrj 			op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
1003*38fd1498Szrj 
1004*38fd1498Szrj     /* If we can prove that one of the arguments (for MINUS_EXPR only
1005*38fd1498Szrj        the second operand, as subtraction is not commutative) is always
1006*38fd1498Szrj        non-negative or always negative, we can do just one comparison
1007*38fd1498Szrj        and conditional jump.  */
1008*38fd1498Szrj     int pos_neg = get_range_pos_neg (arg1);
1009*38fd1498Szrj     if (code == PLUS_EXPR)
1010*38fd1498Szrj       {
1011*38fd1498Szrj 	int pos_neg0 = get_range_pos_neg (arg0);
1012*38fd1498Szrj 	if (pos_neg0 != 3 && pos_neg == 3)
1013*38fd1498Szrj 	  {
1014*38fd1498Szrj 	    std::swap (op0, op1);
1015*38fd1498Szrj 	    pos_neg = pos_neg0;
1016*38fd1498Szrj 	  }
1017*38fd1498Szrj       }
1018*38fd1498Szrj 
1019*38fd1498Szrj     /* Addition overflows if and only if the two operands have the same sign,
1020*38fd1498Szrj        and the result has the opposite sign.  Subtraction overflows if and
1021*38fd1498Szrj        only if the two operands have opposite sign, and the subtrahend has
1022*38fd1498Szrj        the same sign as the result.  Here 0 is counted as positive.  */
1023*38fd1498Szrj     if (pos_neg == 3)
1024*38fd1498Szrj       {
1025*38fd1498Szrj 	/* Compute op0 ^ op1 (operands have opposite sign).  */
1026*38fd1498Szrj         rtx op_xor = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
1027*38fd1498Szrj 				   OPTAB_LIB_WIDEN);
1028*38fd1498Szrj 
1029*38fd1498Szrj 	/* Compute res ^ op1 (result and 2nd operand have opposite sign).  */
1030*38fd1498Szrj 	rtx res_xor = expand_binop (mode, xor_optab, res, op1, NULL_RTX, false,
1031*38fd1498Szrj 				    OPTAB_LIB_WIDEN);
1032*38fd1498Szrj 
1033*38fd1498Szrj 	rtx tem;
1034*38fd1498Szrj 	if (code == PLUS_EXPR)
1035*38fd1498Szrj 	  {
1036*38fd1498Szrj 	    /* Compute (res ^ op1) & ~(op0 ^ op1).  */
1037*38fd1498Szrj 	    tem = expand_unop (mode, one_cmpl_optab, op_xor, NULL_RTX, false);
1038*38fd1498Szrj 	    tem = expand_binop (mode, and_optab, res_xor, tem, NULL_RTX, false,
1039*38fd1498Szrj 				OPTAB_LIB_WIDEN);
1040*38fd1498Szrj 	  }
1041*38fd1498Szrj 	else
1042*38fd1498Szrj 	  {
1043*38fd1498Szrj 	    /* Compute (op0 ^ op1) & ~(res ^ op1).  */
1044*38fd1498Szrj 	    tem = expand_unop (mode, one_cmpl_optab, res_xor, NULL_RTX, false);
1045*38fd1498Szrj 	    tem = expand_binop (mode, and_optab, op_xor, tem, NULL_RTX, false,
1046*38fd1498Szrj 				OPTAB_LIB_WIDEN);
1047*38fd1498Szrj 	  }
1048*38fd1498Szrj 
1049*38fd1498Szrj 	/* No overflow if the result has bit sign cleared.  */
1050*38fd1498Szrj 	do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
1051*38fd1498Szrj 				 NULL, done_label, profile_probability::very_likely ());
1052*38fd1498Szrj       }
1053*38fd1498Szrj 
1054*38fd1498Szrj     /* Compare the result of the operation with the first operand.
1055*38fd1498Szrj        No overflow for addition if second operand is positive and result
1056*38fd1498Szrj        is larger or second operand is negative and result is smaller.
1057*38fd1498Szrj        Likewise for subtraction with sign of second operand flipped.  */
1058*38fd1498Szrj     else
1059*38fd1498Szrj       do_compare_rtx_and_jump (res, op0,
1060*38fd1498Szrj 			       (pos_neg == 1) ^ (code == MINUS_EXPR) ? GE : LE,
1061*38fd1498Szrj 			       false, mode, NULL_RTX, NULL, done_label,
1062*38fd1498Szrj 			       profile_probability::very_likely ());
1063*38fd1498Szrj   }
1064*38fd1498Szrj 
1065*38fd1498Szrj  do_error_label:
1066*38fd1498Szrj   emit_label (do_error);
1067*38fd1498Szrj   if (is_ubsan)
1068*38fd1498Szrj     {
1069*38fd1498Szrj       /* Expand the ubsan builtin call.  */
1070*38fd1498Szrj       push_temp_slots ();
1071*38fd1498Szrj       fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (arg0),
1072*38fd1498Szrj 					 arg0, arg1, datap);
1073*38fd1498Szrj       expand_normal (fn);
1074*38fd1498Szrj       pop_temp_slots ();
1075*38fd1498Szrj       do_pending_stack_adjust ();
1076*38fd1498Szrj     }
1077*38fd1498Szrj   else if (lhs)
1078*38fd1498Szrj     expand_arith_set_overflow (lhs, target);
1079*38fd1498Szrj 
1080*38fd1498Szrj   /* We're done.  */
1081*38fd1498Szrj   emit_label (done_label);
1082*38fd1498Szrj 
1083*38fd1498Szrj   if (lhs)
1084*38fd1498Szrj     {
1085*38fd1498Szrj       if (is_ubsan)
1086*38fd1498Szrj 	expand_ubsan_result_store (target, res);
1087*38fd1498Szrj       else
1088*38fd1498Szrj 	{
1089*38fd1498Szrj 	  if (do_xor)
1090*38fd1498Szrj 	    res = expand_binop (mode, add_optab, res, sgn, NULL_RTX, false,
1091*38fd1498Szrj 				OPTAB_LIB_WIDEN);
1092*38fd1498Szrj 
1093*38fd1498Szrj 	  expand_arith_overflow_result_store (lhs, target, mode, res);
1094*38fd1498Szrj 	}
1095*38fd1498Szrj     }
1096*38fd1498Szrj }
1097*38fd1498Szrj 
1098*38fd1498Szrj /* Add negate overflow checking to the statement STMT.  */
1099*38fd1498Szrj 
1100*38fd1498Szrj static void
expand_neg_overflow(location_t loc,tree lhs,tree arg1,bool is_ubsan,tree * datap)1101*38fd1498Szrj expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan,
1102*38fd1498Szrj 		     tree *datap)
1103*38fd1498Szrj {
1104*38fd1498Szrj   rtx res, op1;
1105*38fd1498Szrj   tree fn;
1106*38fd1498Szrj   rtx_code_label *done_label, *do_error;
1107*38fd1498Szrj   rtx target = NULL_RTX;
1108*38fd1498Szrj 
1109*38fd1498Szrj   done_label = gen_label_rtx ();
1110*38fd1498Szrj   do_error = gen_label_rtx ();
1111*38fd1498Szrj 
1112*38fd1498Szrj   do_pending_stack_adjust ();
1113*38fd1498Szrj   op1 = expand_normal (arg1);
1114*38fd1498Szrj 
1115*38fd1498Szrj   scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg1));
1116*38fd1498Szrj   if (lhs)
1117*38fd1498Szrj     {
1118*38fd1498Szrj       target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
1119*38fd1498Szrj       if (!is_ubsan)
1120*38fd1498Szrj 	write_complex_part (target, const0_rtx, true);
1121*38fd1498Szrj     }
1122*38fd1498Szrj 
1123*38fd1498Szrj   enum insn_code icode = optab_handler (negv3_optab, mode);
1124*38fd1498Szrj   if (icode != CODE_FOR_nothing)
1125*38fd1498Szrj     {
1126*38fd1498Szrj       struct expand_operand ops[3];
1127*38fd1498Szrj       rtx_insn *last = get_last_insn ();
1128*38fd1498Szrj 
1129*38fd1498Szrj       res = gen_reg_rtx (mode);
1130*38fd1498Szrj       create_output_operand (&ops[0], res, mode);
1131*38fd1498Szrj       create_input_operand (&ops[1], op1, mode);
1132*38fd1498Szrj       create_fixed_operand (&ops[2], do_error);
1133*38fd1498Szrj       if (maybe_expand_insn (icode, 3, ops))
1134*38fd1498Szrj 	{
1135*38fd1498Szrj 	  last = get_last_insn ();
1136*38fd1498Szrj 	  if (profile_status_for_fn (cfun) != PROFILE_ABSENT
1137*38fd1498Szrj 	      && JUMP_P (last)
1138*38fd1498Szrj 	      && any_condjump_p (last)
1139*38fd1498Szrj 	      && !find_reg_note (last, REG_BR_PROB, 0))
1140*38fd1498Szrj 	    add_reg_br_prob_note (last,
1141*38fd1498Szrj 				  profile_probability::very_unlikely ());
1142*38fd1498Szrj 	  emit_jump (done_label);
1143*38fd1498Szrj         }
1144*38fd1498Szrj       else
1145*38fd1498Szrj 	{
1146*38fd1498Szrj 	  delete_insns_since (last);
1147*38fd1498Szrj 	  icode = CODE_FOR_nothing;
1148*38fd1498Szrj 	}
1149*38fd1498Szrj     }
1150*38fd1498Szrj 
1151*38fd1498Szrj   if (icode == CODE_FOR_nothing)
1152*38fd1498Szrj     {
1153*38fd1498Szrj       /* Compute the operation.  On RTL level, the addition is always
1154*38fd1498Szrj 	 unsigned.  */
1155*38fd1498Szrj       res = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
1156*38fd1498Szrj 
1157*38fd1498Szrj       /* Compare the operand with the most negative value.  */
1158*38fd1498Szrj       rtx minv = expand_normal (TYPE_MIN_VALUE (TREE_TYPE (arg1)));
1159*38fd1498Szrj       do_compare_rtx_and_jump (op1, minv, NE, true, mode, NULL_RTX, NULL,
1160*38fd1498Szrj 			       done_label, profile_probability::very_likely ());
1161*38fd1498Szrj     }
1162*38fd1498Szrj 
1163*38fd1498Szrj   emit_label (do_error);
1164*38fd1498Szrj   if (is_ubsan)
1165*38fd1498Szrj     {
1166*38fd1498Szrj       /* Expand the ubsan builtin call.  */
1167*38fd1498Szrj       push_temp_slots ();
1168*38fd1498Szrj       fn = ubsan_build_overflow_builtin (NEGATE_EXPR, loc, TREE_TYPE (arg1),
1169*38fd1498Szrj 					 arg1, NULL_TREE, datap);
1170*38fd1498Szrj       expand_normal (fn);
1171*38fd1498Szrj       pop_temp_slots ();
1172*38fd1498Szrj       do_pending_stack_adjust ();
1173*38fd1498Szrj     }
1174*38fd1498Szrj   else if (lhs)
1175*38fd1498Szrj     expand_arith_set_overflow (lhs, target);
1176*38fd1498Szrj 
1177*38fd1498Szrj   /* We're done.  */
1178*38fd1498Szrj   emit_label (done_label);
1179*38fd1498Szrj 
1180*38fd1498Szrj   if (lhs)
1181*38fd1498Szrj     {
1182*38fd1498Szrj       if (is_ubsan)
1183*38fd1498Szrj 	expand_ubsan_result_store (target, res);
1184*38fd1498Szrj       else
1185*38fd1498Szrj 	expand_arith_overflow_result_store (lhs, target, mode, res);
1186*38fd1498Szrj     }
1187*38fd1498Szrj }
1188*38fd1498Szrj 
1189*38fd1498Szrj /* Return true if UNS WIDEN_MULT_EXPR with result mode WMODE and operand
1190*38fd1498Szrj    mode MODE can be expanded without using a libcall.  */
1191*38fd1498Szrj 
1192*38fd1498Szrj static bool
can_widen_mult_without_libcall(scalar_int_mode wmode,scalar_int_mode mode,rtx op0,rtx op1,bool uns)1193*38fd1498Szrj can_widen_mult_without_libcall (scalar_int_mode wmode, scalar_int_mode mode,
1194*38fd1498Szrj 				rtx op0, rtx op1, bool uns)
1195*38fd1498Szrj {
1196*38fd1498Szrj   if (find_widening_optab_handler (umul_widen_optab, wmode, mode)
1197*38fd1498Szrj       != CODE_FOR_nothing)
1198*38fd1498Szrj     return true;
1199*38fd1498Szrj 
1200*38fd1498Szrj   if (find_widening_optab_handler (smul_widen_optab, wmode, mode)
1201*38fd1498Szrj       != CODE_FOR_nothing)
1202*38fd1498Szrj     return true;
1203*38fd1498Szrj 
1204*38fd1498Szrj   rtx_insn *last = get_last_insn ();
1205*38fd1498Szrj   if (CONSTANT_P (op0))
1206*38fd1498Szrj     op0 = convert_modes (wmode, mode, op0, uns);
1207*38fd1498Szrj   else
1208*38fd1498Szrj     op0 = gen_raw_REG (wmode, LAST_VIRTUAL_REGISTER + 1);
1209*38fd1498Szrj   if (CONSTANT_P (op1))
1210*38fd1498Szrj     op1 = convert_modes (wmode, mode, op1, uns);
1211*38fd1498Szrj   else
1212*38fd1498Szrj     op1 = gen_raw_REG (wmode, LAST_VIRTUAL_REGISTER + 2);
1213*38fd1498Szrj   rtx ret = expand_mult (wmode, op0, op1, NULL_RTX, uns, true);
1214*38fd1498Szrj   delete_insns_since (last);
1215*38fd1498Szrj   return ret != NULL_RTX;
1216*38fd1498Szrj }
1217*38fd1498Szrj 
1218*38fd1498Szrj /* Add mul overflow checking to the statement STMT.  */
1219*38fd1498Szrj 
1220*38fd1498Szrj static void
expand_mul_overflow(location_t loc,tree lhs,tree arg0,tree arg1,bool unsr_p,bool uns0_p,bool uns1_p,bool is_ubsan,tree * datap)1221*38fd1498Szrj expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
1222*38fd1498Szrj 		     bool unsr_p, bool uns0_p, bool uns1_p, bool is_ubsan,
1223*38fd1498Szrj 		     tree *datap)
1224*38fd1498Szrj {
1225*38fd1498Szrj   rtx res, op0, op1;
1226*38fd1498Szrj   tree fn, type;
1227*38fd1498Szrj   rtx_code_label *done_label, *do_error;
1228*38fd1498Szrj   rtx target = NULL_RTX;
1229*38fd1498Szrj   signop sign;
1230*38fd1498Szrj   enum insn_code icode;
1231*38fd1498Szrj 
1232*38fd1498Szrj   done_label = gen_label_rtx ();
1233*38fd1498Szrj   do_error = gen_label_rtx ();
1234*38fd1498Szrj 
1235*38fd1498Szrj   do_pending_stack_adjust ();
1236*38fd1498Szrj   op0 = expand_normal (arg0);
1237*38fd1498Szrj   op1 = expand_normal (arg1);
1238*38fd1498Szrj 
1239*38fd1498Szrj   scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg0));
1240*38fd1498Szrj   bool uns = unsr_p;
1241*38fd1498Szrj   if (lhs)
1242*38fd1498Szrj     {
1243*38fd1498Szrj       target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
1244*38fd1498Szrj       if (!is_ubsan)
1245*38fd1498Szrj 	write_complex_part (target, const0_rtx, true);
1246*38fd1498Szrj     }
1247*38fd1498Szrj 
1248*38fd1498Szrj   if (is_ubsan)
1249*38fd1498Szrj     gcc_assert (!unsr_p && !uns0_p && !uns1_p);
1250*38fd1498Szrj 
1251*38fd1498Szrj   /* We assume both operands and result have the same precision
1252*38fd1498Szrj      here (GET_MODE_BITSIZE (mode)), S stands for signed type
1253*38fd1498Szrj      with that precision, U for unsigned type with that precision,
1254*38fd1498Szrj      sgn for unsigned most significant bit in that precision.
1255*38fd1498Szrj      s1 is signed first operand, u1 is unsigned first operand,
1256*38fd1498Szrj      s2 is signed second operand, u2 is unsigned second operand,
1257*38fd1498Szrj      sr is signed result, ur is unsigned result and the following
1258*38fd1498Szrj      rules say how to compute result (which is always result of
1259*38fd1498Szrj      the operands as if both were unsigned, cast to the right
1260*38fd1498Szrj      signedness) and how to compute whether operation overflowed.
1261*38fd1498Szrj      main_ovf (false) stands for jump on signed multiplication
1262*38fd1498Szrj      overflow or the main algorithm with uns == false.
1263*38fd1498Szrj      main_ovf (true) stands for jump on unsigned multiplication
1264*38fd1498Szrj      overflow or the main algorithm with uns == true.
1265*38fd1498Szrj 
1266*38fd1498Szrj      s1 * s2 -> sr
1267*38fd1498Szrj 	res = (S) ((U) s1 * (U) s2)
1268*38fd1498Szrj 	ovf = main_ovf (false)
1269*38fd1498Szrj      u1 * u2 -> ur
1270*38fd1498Szrj 	res = u1 * u2
1271*38fd1498Szrj 	ovf = main_ovf (true)
1272*38fd1498Szrj      s1 * u2 -> ur
1273*38fd1498Szrj 	res = (U) s1 * u2
1274*38fd1498Szrj 	ovf = (s1 < 0 && u2) || main_ovf (true)
1275*38fd1498Szrj      u1 * u2 -> sr
1276*38fd1498Szrj 	res = (S) (u1 * u2)
1277*38fd1498Szrj 	ovf = res < 0 || main_ovf (true)
1278*38fd1498Szrj      s1 * u2 -> sr
1279*38fd1498Szrj 	res = (S) ((U) s1 * u2)
1280*38fd1498Szrj 	ovf = (S) u2 >= 0 ? main_ovf (false)
1281*38fd1498Szrj 			  : (s1 != 0 && (s1 != -1 || u2 != (U) res))
1282*38fd1498Szrj      s1 * s2 -> ur
1283*38fd1498Szrj 	t1 = (s1 & s2) < 0 ? (-(U) s1) : ((U) s1)
1284*38fd1498Szrj 	t2 = (s1 & s2) < 0 ? (-(U) s2) : ((U) s2)
1285*38fd1498Szrj 	res = t1 * t2
1286*38fd1498Szrj 	ovf = (s1 ^ s2) < 0 ? (s1 && s2) : main_ovf (true)  */
1287*38fd1498Szrj 
1288*38fd1498Szrj   if (uns0_p && !uns1_p)
1289*38fd1498Szrj     {
1290*38fd1498Szrj       /* Multiplication is commutative, if operand signedness differs,
1291*38fd1498Szrj 	 canonicalize to the first operand being signed and second
1292*38fd1498Szrj 	 unsigned to simplify following code.  */
1293*38fd1498Szrj       std::swap (op0, op1);
1294*38fd1498Szrj       std::swap (arg0, arg1);
1295*38fd1498Szrj       uns0_p = false;
1296*38fd1498Szrj       uns1_p = true;
1297*38fd1498Szrj     }
1298*38fd1498Szrj 
1299*38fd1498Szrj   int pos_neg0 = get_range_pos_neg (arg0);
1300*38fd1498Szrj   int pos_neg1 = get_range_pos_neg (arg1);
1301*38fd1498Szrj 
1302*38fd1498Szrj   /* s1 * u2 -> ur  */
1303*38fd1498Szrj   if (!uns0_p && uns1_p && unsr_p)
1304*38fd1498Szrj     {
1305*38fd1498Szrj       switch (pos_neg0)
1306*38fd1498Szrj 	{
1307*38fd1498Szrj 	case 1:
1308*38fd1498Szrj 	  /* If s1 is non-negative, just perform normal u1 * u2 -> ur.  */
1309*38fd1498Szrj 	  goto do_main;
1310*38fd1498Szrj 	case 2:
1311*38fd1498Szrj 	  /* If s1 is negative, avoid the main code, just multiply and
1312*38fd1498Szrj 	     signal overflow if op1 is not 0.  */
1313*38fd1498Szrj 	  struct separate_ops ops;
1314*38fd1498Szrj 	  ops.code = MULT_EXPR;
1315*38fd1498Szrj 	  ops.type = TREE_TYPE (arg1);
1316*38fd1498Szrj 	  ops.op0 = make_tree (ops.type, op0);
1317*38fd1498Szrj 	  ops.op1 = make_tree (ops.type, op1);
1318*38fd1498Szrj 	  ops.op2 = NULL_TREE;
1319*38fd1498Szrj 	  ops.location = loc;
1320*38fd1498Szrj 	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1321*38fd1498Szrj 	  do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
1322*38fd1498Szrj 				   NULL, done_label, profile_probability::very_likely ());
1323*38fd1498Szrj 	  goto do_error_label;
1324*38fd1498Szrj 	case 3:
1325*38fd1498Szrj 	  rtx_code_label *do_main_label;
1326*38fd1498Szrj 	  do_main_label = gen_label_rtx ();
1327*38fd1498Szrj 	  do_compare_rtx_and_jump (op0, const0_rtx, GE, false, mode, NULL_RTX,
1328*38fd1498Szrj 				   NULL, do_main_label, profile_probability::very_likely ());
1329*38fd1498Szrj 	  do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
1330*38fd1498Szrj 				   NULL, do_main_label, profile_probability::very_likely ());
1331*38fd1498Szrj 	  expand_arith_set_overflow (lhs, target);
1332*38fd1498Szrj 	  emit_label (do_main_label);
1333*38fd1498Szrj 	  goto do_main;
1334*38fd1498Szrj 	default:
1335*38fd1498Szrj 	  gcc_unreachable ();
1336*38fd1498Szrj 	}
1337*38fd1498Szrj     }
1338*38fd1498Szrj 
1339*38fd1498Szrj   /* u1 * u2 -> sr  */
1340*38fd1498Szrj   if (uns0_p && uns1_p && !unsr_p)
1341*38fd1498Szrj     {
1342*38fd1498Szrj       uns = true;
1343*38fd1498Szrj       /* Rest of handling of this case after res is computed.  */
1344*38fd1498Szrj       goto do_main;
1345*38fd1498Szrj     }
1346*38fd1498Szrj 
1347*38fd1498Szrj   /* s1 * u2 -> sr  */
1348*38fd1498Szrj   if (!uns0_p && uns1_p && !unsr_p)
1349*38fd1498Szrj     {
1350*38fd1498Szrj       switch (pos_neg1)
1351*38fd1498Szrj 	{
1352*38fd1498Szrj 	case 1:
1353*38fd1498Szrj 	  goto do_main;
1354*38fd1498Szrj 	case 2:
1355*38fd1498Szrj 	  /* If (S) u2 is negative (i.e. u2 is larger than maximum of S,
1356*38fd1498Szrj 	     avoid the main code, just multiply and signal overflow
1357*38fd1498Szrj 	     unless 0 * u2 or -1 * ((U) Smin).  */
1358*38fd1498Szrj 	  struct separate_ops ops;
1359*38fd1498Szrj 	  ops.code = MULT_EXPR;
1360*38fd1498Szrj 	  ops.type = TREE_TYPE (arg1);
1361*38fd1498Szrj 	  ops.op0 = make_tree (ops.type, op0);
1362*38fd1498Szrj 	  ops.op1 = make_tree (ops.type, op1);
1363*38fd1498Szrj 	  ops.op2 = NULL_TREE;
1364*38fd1498Szrj 	  ops.location = loc;
1365*38fd1498Szrj 	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1366*38fd1498Szrj 	  do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
1367*38fd1498Szrj 				   NULL, done_label, profile_probability::very_likely ());
1368*38fd1498Szrj 	  do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
1369*38fd1498Szrj 				   NULL, do_error, profile_probability::very_unlikely ());
1370*38fd1498Szrj 	  int prec;
1371*38fd1498Szrj 	  prec = GET_MODE_PRECISION (mode);
1372*38fd1498Szrj 	  rtx sgn;
1373*38fd1498Szrj 	  sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
1374*38fd1498Szrj 	  do_compare_rtx_and_jump (op1, sgn, EQ, true, mode, NULL_RTX,
1375*38fd1498Szrj 				   NULL, done_label, profile_probability::very_likely ());
1376*38fd1498Szrj 	  goto do_error_label;
1377*38fd1498Szrj 	case 3:
1378*38fd1498Szrj 	  /* Rest of handling of this case after res is computed.  */
1379*38fd1498Szrj 	  goto do_main;
1380*38fd1498Szrj 	default:
1381*38fd1498Szrj 	  gcc_unreachable ();
1382*38fd1498Szrj 	}
1383*38fd1498Szrj     }
1384*38fd1498Szrj 
1385*38fd1498Szrj   /* s1 * s2 -> ur  */
1386*38fd1498Szrj   if (!uns0_p && !uns1_p && unsr_p)
1387*38fd1498Szrj     {
1388*38fd1498Szrj       rtx tem, tem2;
1389*38fd1498Szrj       switch (pos_neg0 | pos_neg1)
1390*38fd1498Szrj 	{
1391*38fd1498Szrj 	case 1: /* Both operands known to be non-negative.  */
1392*38fd1498Szrj 	  goto do_main;
1393*38fd1498Szrj 	case 2: /* Both operands known to be negative.  */
1394*38fd1498Szrj 	  op0 = expand_unop (mode, neg_optab, op0, NULL_RTX, false);
1395*38fd1498Szrj 	  op1 = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
1396*38fd1498Szrj 	  /* Avoid looking at arg0/arg1 ranges, as we've changed
1397*38fd1498Szrj 	     the arguments.  */
1398*38fd1498Szrj 	  arg0 = error_mark_node;
1399*38fd1498Szrj 	  arg1 = error_mark_node;
1400*38fd1498Szrj 	  goto do_main;
1401*38fd1498Szrj 	case 3:
1402*38fd1498Szrj 	  if ((pos_neg0 ^ pos_neg1) == 3)
1403*38fd1498Szrj 	    {
1404*38fd1498Szrj 	      /* If one operand is known to be negative and the other
1405*38fd1498Szrj 		 non-negative, this overflows always, unless the non-negative
1406*38fd1498Szrj 		 one is 0.  Just do normal multiply and set overflow
1407*38fd1498Szrj 		 unless one of the operands is 0.  */
1408*38fd1498Szrj 	      struct separate_ops ops;
1409*38fd1498Szrj 	      ops.code = MULT_EXPR;
1410*38fd1498Szrj 	      ops.type
1411*38fd1498Szrj 		= build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
1412*38fd1498Szrj 						  1);
1413*38fd1498Szrj 	      ops.op0 = make_tree (ops.type, op0);
1414*38fd1498Szrj 	      ops.op1 = make_tree (ops.type, op1);
1415*38fd1498Szrj 	      ops.op2 = NULL_TREE;
1416*38fd1498Szrj 	      ops.location = loc;
1417*38fd1498Szrj 	      res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1418*38fd1498Szrj 	      tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false,
1419*38fd1498Szrj 				  OPTAB_LIB_WIDEN);
1420*38fd1498Szrj 	      do_compare_rtx_and_jump (tem, const0_rtx, EQ, true, mode,
1421*38fd1498Szrj 				       NULL_RTX, NULL, done_label,
1422*38fd1498Szrj 				       profile_probability::very_likely ());
1423*38fd1498Szrj 	      goto do_error_label;
1424*38fd1498Szrj 	    }
1425*38fd1498Szrj 	  /* The general case, do all the needed comparisons at runtime.  */
1426*38fd1498Szrj 	  rtx_code_label *do_main_label, *after_negate_label;
1427*38fd1498Szrj 	  rtx rop0, rop1;
1428*38fd1498Szrj 	  rop0 = gen_reg_rtx (mode);
1429*38fd1498Szrj 	  rop1 = gen_reg_rtx (mode);
1430*38fd1498Szrj 	  emit_move_insn (rop0, op0);
1431*38fd1498Szrj 	  emit_move_insn (rop1, op1);
1432*38fd1498Szrj 	  op0 = rop0;
1433*38fd1498Szrj 	  op1 = rop1;
1434*38fd1498Szrj 	  do_main_label = gen_label_rtx ();
1435*38fd1498Szrj 	  after_negate_label = gen_label_rtx ();
1436*38fd1498Szrj 	  tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false,
1437*38fd1498Szrj 			      OPTAB_LIB_WIDEN);
1438*38fd1498Szrj 	  do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
1439*38fd1498Szrj 				   NULL, after_negate_label, profile_probability::very_likely ());
1440*38fd1498Szrj 	  /* Both arguments negative here, negate them and continue with
1441*38fd1498Szrj 	     normal unsigned overflow checking multiplication.  */
1442*38fd1498Szrj 	  emit_move_insn (op0, expand_unop (mode, neg_optab, op0,
1443*38fd1498Szrj 					    NULL_RTX, false));
1444*38fd1498Szrj 	  emit_move_insn (op1, expand_unop (mode, neg_optab, op1,
1445*38fd1498Szrj 					    NULL_RTX, false));
1446*38fd1498Szrj 	  /* Avoid looking at arg0/arg1 ranges, as we might have changed
1447*38fd1498Szrj 	     the arguments.  */
1448*38fd1498Szrj 	  arg0 = error_mark_node;
1449*38fd1498Szrj 	  arg1 = error_mark_node;
1450*38fd1498Szrj 	  emit_jump (do_main_label);
1451*38fd1498Szrj 	  emit_label (after_negate_label);
1452*38fd1498Szrj 	  tem2 = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
1453*38fd1498Szrj 			       OPTAB_LIB_WIDEN);
1454*38fd1498Szrj 	  do_compare_rtx_and_jump (tem2, const0_rtx, GE, false, mode, NULL_RTX,
1455*38fd1498Szrj 				   NULL, do_main_label, profile_probability::very_likely ());
1456*38fd1498Szrj 	  /* One argument is negative here, the other positive.  This
1457*38fd1498Szrj 	     overflows always, unless one of the arguments is 0.  But
1458*38fd1498Szrj 	     if e.g. s2 is 0, (U) s1 * 0 doesn't overflow, whatever s1
1459*38fd1498Szrj 	     is, thus we can keep do_main code oring in overflow as is.  */
1460*38fd1498Szrj 	  do_compare_rtx_and_jump (tem, const0_rtx, EQ, true, mode, NULL_RTX,
1461*38fd1498Szrj 				   NULL, do_main_label, profile_probability::very_likely ());
1462*38fd1498Szrj 	  expand_arith_set_overflow (lhs, target);
1463*38fd1498Szrj 	  emit_label (do_main_label);
1464*38fd1498Szrj 	  goto do_main;
1465*38fd1498Szrj 	default:
1466*38fd1498Szrj 	  gcc_unreachable ();
1467*38fd1498Szrj 	}
1468*38fd1498Szrj     }
1469*38fd1498Szrj 
1470*38fd1498Szrj  do_main:
1471*38fd1498Szrj   type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode), uns);
1472*38fd1498Szrj   sign = uns ? UNSIGNED : SIGNED;
1473*38fd1498Szrj   icode = optab_handler (uns ? umulv4_optab : mulv4_optab, mode);
1474*38fd1498Szrj   if (uns
1475*38fd1498Szrj       && (integer_pow2p (arg0) || integer_pow2p (arg1))
1476*38fd1498Szrj       && (optimize_insn_for_speed_p () || icode == CODE_FOR_nothing))
1477*38fd1498Szrj     {
1478*38fd1498Szrj       /* Optimize unsigned multiplication by power of 2 constant
1479*38fd1498Szrj 	 using 2 shifts, one for result, one to extract the shifted
1480*38fd1498Szrj 	 out bits to see if they are all zero.
1481*38fd1498Szrj 	 Don't do this if optimizing for size and we have umulv4_optab,
1482*38fd1498Szrj 	 in that case assume multiplication will be shorter.
1483*38fd1498Szrj 	 This is heuristics based on the single target that provides
1484*38fd1498Szrj 	 umulv4 right now (i?86/x86_64), if further targets add it, this
1485*38fd1498Szrj 	 might need to be revisited.
1486*38fd1498Szrj 	 Cases where both operands are constant should be folded already
1487*38fd1498Szrj 	 during GIMPLE, and cases where one operand is constant but not
1488*38fd1498Szrj 	 power of 2 are questionable, either the WIDEN_MULT_EXPR case
1489*38fd1498Szrj 	 below can be done without multiplication, just by shifts and adds,
1490*38fd1498Szrj 	 or we'd need to divide the result (and hope it actually doesn't
1491*38fd1498Szrj 	 really divide nor multiply) and compare the result of the division
1492*38fd1498Szrj 	 with the original operand.  */
1493*38fd1498Szrj       rtx opn0 = op0;
1494*38fd1498Szrj       rtx opn1 = op1;
1495*38fd1498Szrj       tree argn0 = arg0;
1496*38fd1498Szrj       tree argn1 = arg1;
1497*38fd1498Szrj       if (integer_pow2p (arg0))
1498*38fd1498Szrj 	{
1499*38fd1498Szrj 	  std::swap (opn0, opn1);
1500*38fd1498Szrj 	  std::swap (argn0, argn1);
1501*38fd1498Szrj 	}
1502*38fd1498Szrj       int cnt = tree_log2 (argn1);
1503*38fd1498Szrj       if (cnt >= 0 && cnt < GET_MODE_PRECISION (mode))
1504*38fd1498Szrj 	{
1505*38fd1498Szrj 	  rtx upper = const0_rtx;
1506*38fd1498Szrj 	  res = expand_shift (LSHIFT_EXPR, mode, opn0, cnt, NULL_RTX, uns);
1507*38fd1498Szrj 	  if (cnt != 0)
1508*38fd1498Szrj 	    upper = expand_shift (RSHIFT_EXPR, mode, opn0,
1509*38fd1498Szrj 				  GET_MODE_PRECISION (mode) - cnt,
1510*38fd1498Szrj 				  NULL_RTX, uns);
1511*38fd1498Szrj 	  do_compare_rtx_and_jump (upper, const0_rtx, EQ, true, mode,
1512*38fd1498Szrj 				   NULL_RTX, NULL, done_label,
1513*38fd1498Szrj 				   profile_probability::very_likely ());
1514*38fd1498Szrj 	  goto do_error_label;
1515*38fd1498Szrj 	}
1516*38fd1498Szrj     }
1517*38fd1498Szrj   if (icode != CODE_FOR_nothing)
1518*38fd1498Szrj     {
1519*38fd1498Szrj       struct expand_operand ops[4];
1520*38fd1498Szrj       rtx_insn *last = get_last_insn ();
1521*38fd1498Szrj 
1522*38fd1498Szrj       res = gen_reg_rtx (mode);
1523*38fd1498Szrj       create_output_operand (&ops[0], res, mode);
1524*38fd1498Szrj       create_input_operand (&ops[1], op0, mode);
1525*38fd1498Szrj       create_input_operand (&ops[2], op1, mode);
1526*38fd1498Szrj       create_fixed_operand (&ops[3], do_error);
1527*38fd1498Szrj       if (maybe_expand_insn (icode, 4, ops))
1528*38fd1498Szrj 	{
1529*38fd1498Szrj 	  last = get_last_insn ();
1530*38fd1498Szrj 	  if (profile_status_for_fn (cfun) != PROFILE_ABSENT
1531*38fd1498Szrj 	      && JUMP_P (last)
1532*38fd1498Szrj 	      && any_condjump_p (last)
1533*38fd1498Szrj 	      && !find_reg_note (last, REG_BR_PROB, 0))
1534*38fd1498Szrj 	    add_reg_br_prob_note (last,
1535*38fd1498Szrj 				  profile_probability::very_unlikely ());
1536*38fd1498Szrj 	  emit_jump (done_label);
1537*38fd1498Szrj         }
1538*38fd1498Szrj       else
1539*38fd1498Szrj 	{
1540*38fd1498Szrj 	  delete_insns_since (last);
1541*38fd1498Szrj 	  icode = CODE_FOR_nothing;
1542*38fd1498Szrj 	}
1543*38fd1498Szrj     }
1544*38fd1498Szrj 
1545*38fd1498Szrj   if (icode == CODE_FOR_nothing)
1546*38fd1498Szrj     {
1547*38fd1498Szrj       struct separate_ops ops;
1548*38fd1498Szrj       int prec = GET_MODE_PRECISION (mode);
1549*38fd1498Szrj       scalar_int_mode hmode, wmode;
1550*38fd1498Szrj       ops.op0 = make_tree (type, op0);
1551*38fd1498Szrj       ops.op1 = make_tree (type, op1);
1552*38fd1498Szrj       ops.op2 = NULL_TREE;
1553*38fd1498Szrj       ops.location = loc;
1554*38fd1498Szrj 
1555*38fd1498Szrj       /* Optimize unsigned overflow check where we don't use the
1556*38fd1498Szrj 	 multiplication result, just whether overflow happened.
1557*38fd1498Szrj 	 If we can do MULT_HIGHPART_EXPR, that followed by
1558*38fd1498Szrj 	 comparison of the result against zero is cheapest.
1559*38fd1498Szrj 	 We'll still compute res, but it should be DCEd later.  */
1560*38fd1498Szrj       use_operand_p use;
1561*38fd1498Szrj       gimple *use_stmt;
1562*38fd1498Szrj       if (!is_ubsan
1563*38fd1498Szrj 	  && lhs
1564*38fd1498Szrj 	  && uns
1565*38fd1498Szrj 	  && !(uns0_p && uns1_p && !unsr_p)
1566*38fd1498Szrj 	  && can_mult_highpart_p (mode, uns) == 1
1567*38fd1498Szrj 	  && single_imm_use (lhs, &use, &use_stmt)
1568*38fd1498Szrj 	  && is_gimple_assign (use_stmt)
1569*38fd1498Szrj 	  && gimple_assign_rhs_code (use_stmt) == IMAGPART_EXPR)
1570*38fd1498Szrj 	goto highpart;
1571*38fd1498Szrj 
1572*38fd1498Szrj       if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
1573*38fd1498Szrj 	  && targetm.scalar_mode_supported_p (wmode)
1574*38fd1498Szrj 	  && can_widen_mult_without_libcall (wmode, mode, op0, op1, uns))
1575*38fd1498Szrj 	{
1576*38fd1498Szrj 	twoxwider:
1577*38fd1498Szrj 	  ops.code = WIDEN_MULT_EXPR;
1578*38fd1498Szrj 	  ops.type
1579*38fd1498Szrj 	    = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), uns);
1580*38fd1498Szrj 
1581*38fd1498Szrj 	  res = expand_expr_real_2 (&ops, NULL_RTX, wmode, EXPAND_NORMAL);
1582*38fd1498Szrj 	  rtx hipart = expand_shift (RSHIFT_EXPR, wmode, res, prec,
1583*38fd1498Szrj 				     NULL_RTX, uns);
1584*38fd1498Szrj 	  hipart = convert_modes (mode, wmode, hipart, uns);
1585*38fd1498Szrj 	  res = convert_modes (mode, wmode, res, uns);
1586*38fd1498Szrj 	  if (uns)
1587*38fd1498Szrj 	    /* For the unsigned multiplication, there was overflow if
1588*38fd1498Szrj 	       HIPART is non-zero.  */
1589*38fd1498Szrj 	    do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
1590*38fd1498Szrj 				     NULL_RTX, NULL, done_label,
1591*38fd1498Szrj 				     profile_probability::very_likely ());
1592*38fd1498Szrj 	  else
1593*38fd1498Szrj 	    {
1594*38fd1498Szrj 	      rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
1595*38fd1498Szrj 					  NULL_RTX, 0);
1596*38fd1498Szrj 	      /* RES is low half of the double width result, HIPART
1597*38fd1498Szrj 		 the high half.  There was overflow if
1598*38fd1498Szrj 		 HIPART is different from RES < 0 ? -1 : 0.  */
1599*38fd1498Szrj 	      do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
1600*38fd1498Szrj 				       NULL_RTX, NULL, done_label,
1601*38fd1498Szrj 				       profile_probability::very_likely ());
1602*38fd1498Szrj 	    }
1603*38fd1498Szrj 	}
1604*38fd1498Szrj       else if (can_mult_highpart_p (mode, uns) == 1)
1605*38fd1498Szrj 	{
1606*38fd1498Szrj 	highpart:
1607*38fd1498Szrj 	  ops.code = MULT_HIGHPART_EXPR;
1608*38fd1498Szrj 	  ops.type = type;
1609*38fd1498Szrj 
1610*38fd1498Szrj 	  rtx hipart = expand_expr_real_2 (&ops, NULL_RTX, mode,
1611*38fd1498Szrj 					   EXPAND_NORMAL);
1612*38fd1498Szrj 	  ops.code = MULT_EXPR;
1613*38fd1498Szrj 	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1614*38fd1498Szrj 	  if (uns)
1615*38fd1498Szrj 	    /* For the unsigned multiplication, there was overflow if
1616*38fd1498Szrj 	       HIPART is non-zero.  */
1617*38fd1498Szrj 	    do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
1618*38fd1498Szrj 				     NULL_RTX, NULL, done_label,
1619*38fd1498Szrj 				     profile_probability::very_likely ());
1620*38fd1498Szrj 	  else
1621*38fd1498Szrj 	    {
1622*38fd1498Szrj 	      rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
1623*38fd1498Szrj 					  NULL_RTX, 0);
1624*38fd1498Szrj 	      /* RES is low half of the double width result, HIPART
1625*38fd1498Szrj 		 the high half.  There was overflow if
1626*38fd1498Szrj 		 HIPART is different from RES < 0 ? -1 : 0.  */
1627*38fd1498Szrj 	      do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
1628*38fd1498Szrj 				       NULL_RTX, NULL, done_label,
1629*38fd1498Szrj 				       profile_probability::very_likely ());
1630*38fd1498Szrj 	    }
1631*38fd1498Szrj 
1632*38fd1498Szrj 	}
1633*38fd1498Szrj       else if (int_mode_for_size (prec / 2, 1).exists (&hmode)
1634*38fd1498Szrj 	       && 2 * GET_MODE_PRECISION (hmode) == prec)
1635*38fd1498Szrj 	{
1636*38fd1498Szrj 	  rtx_code_label *large_op0 = gen_label_rtx ();
1637*38fd1498Szrj 	  rtx_code_label *small_op0_large_op1 = gen_label_rtx ();
1638*38fd1498Szrj 	  rtx_code_label *one_small_one_large = gen_label_rtx ();
1639*38fd1498Szrj 	  rtx_code_label *both_ops_large = gen_label_rtx ();
1640*38fd1498Szrj 	  rtx_code_label *after_hipart_neg = uns ? NULL : gen_label_rtx ();
1641*38fd1498Szrj 	  rtx_code_label *after_lopart_neg = uns ? NULL : gen_label_rtx ();
1642*38fd1498Szrj 	  rtx_code_label *do_overflow = gen_label_rtx ();
1643*38fd1498Szrj 	  rtx_code_label *hipart_different = uns ? NULL : gen_label_rtx ();
1644*38fd1498Szrj 
1645*38fd1498Szrj 	  unsigned int hprec = GET_MODE_PRECISION (hmode);
1646*38fd1498Szrj 	  rtx hipart0 = expand_shift (RSHIFT_EXPR, mode, op0, hprec,
1647*38fd1498Szrj 				      NULL_RTX, uns);
1648*38fd1498Szrj 	  hipart0 = convert_modes (hmode, mode, hipart0, uns);
1649*38fd1498Szrj 	  rtx lopart0 = convert_modes (hmode, mode, op0, uns);
1650*38fd1498Szrj 	  rtx signbit0 = const0_rtx;
1651*38fd1498Szrj 	  if (!uns)
1652*38fd1498Szrj 	    signbit0 = expand_shift (RSHIFT_EXPR, hmode, lopart0, hprec - 1,
1653*38fd1498Szrj 				     NULL_RTX, 0);
1654*38fd1498Szrj 	  rtx hipart1 = expand_shift (RSHIFT_EXPR, mode, op1, hprec,
1655*38fd1498Szrj 				      NULL_RTX, uns);
1656*38fd1498Szrj 	  hipart1 = convert_modes (hmode, mode, hipart1, uns);
1657*38fd1498Szrj 	  rtx lopart1 = convert_modes (hmode, mode, op1, uns);
1658*38fd1498Szrj 	  rtx signbit1 = const0_rtx;
1659*38fd1498Szrj 	  if (!uns)
1660*38fd1498Szrj 	    signbit1 = expand_shift (RSHIFT_EXPR, hmode, lopart1, hprec - 1,
1661*38fd1498Szrj 				     NULL_RTX, 0);
1662*38fd1498Szrj 
1663*38fd1498Szrj 	  res = gen_reg_rtx (mode);
1664*38fd1498Szrj 
1665*38fd1498Szrj 	  /* True if op0 resp. op1 are known to be in the range of
1666*38fd1498Szrj 	     halfstype.  */
1667*38fd1498Szrj 	  bool op0_small_p = false;
1668*38fd1498Szrj 	  bool op1_small_p = false;
1669*38fd1498Szrj 	  /* True if op0 resp. op1 are known to have all zeros or all ones
1670*38fd1498Szrj 	     in the upper half of bits, but are not known to be
1671*38fd1498Szrj 	     op{0,1}_small_p.  */
1672*38fd1498Szrj 	  bool op0_medium_p = false;
1673*38fd1498Szrj 	  bool op1_medium_p = false;
1674*38fd1498Szrj 	  /* -1 if op{0,1} is known to be negative, 0 if it is known to be
1675*38fd1498Szrj 	     nonnegative, 1 if unknown.  */
1676*38fd1498Szrj 	  int op0_sign = 1;
1677*38fd1498Szrj 	  int op1_sign = 1;
1678*38fd1498Szrj 
1679*38fd1498Szrj 	  if (pos_neg0 == 1)
1680*38fd1498Szrj 	    op0_sign = 0;
1681*38fd1498Szrj 	  else if (pos_neg0 == 2)
1682*38fd1498Szrj 	    op0_sign = -1;
1683*38fd1498Szrj 	  if (pos_neg1 == 1)
1684*38fd1498Szrj 	    op1_sign = 0;
1685*38fd1498Szrj 	  else if (pos_neg1 == 2)
1686*38fd1498Szrj 	    op1_sign = -1;
1687*38fd1498Szrj 
1688*38fd1498Szrj 	  unsigned int mprec0 = prec;
1689*38fd1498Szrj 	  if (arg0 != error_mark_node)
1690*38fd1498Szrj 	    mprec0 = get_min_precision (arg0, sign);
1691*38fd1498Szrj 	  if (mprec0 <= hprec)
1692*38fd1498Szrj 	    op0_small_p = true;
1693*38fd1498Szrj 	  else if (!uns && mprec0 <= hprec + 1)
1694*38fd1498Szrj 	    op0_medium_p = true;
1695*38fd1498Szrj 	  unsigned int mprec1 = prec;
1696*38fd1498Szrj 	  if (arg1 != error_mark_node)
1697*38fd1498Szrj 	    mprec1 = get_min_precision (arg1, sign);
1698*38fd1498Szrj 	  if (mprec1 <= hprec)
1699*38fd1498Szrj 	    op1_small_p = true;
1700*38fd1498Szrj 	  else if (!uns && mprec1 <= hprec + 1)
1701*38fd1498Szrj 	    op1_medium_p = true;
1702*38fd1498Szrj 
1703*38fd1498Szrj 	  int smaller_sign = 1;
1704*38fd1498Szrj 	  int larger_sign = 1;
1705*38fd1498Szrj 	  if (op0_small_p)
1706*38fd1498Szrj 	    {
1707*38fd1498Szrj 	      smaller_sign = op0_sign;
1708*38fd1498Szrj 	      larger_sign = op1_sign;
1709*38fd1498Szrj 	    }
1710*38fd1498Szrj 	  else if (op1_small_p)
1711*38fd1498Szrj 	    {
1712*38fd1498Szrj 	      smaller_sign = op1_sign;
1713*38fd1498Szrj 	      larger_sign = op0_sign;
1714*38fd1498Szrj 	    }
1715*38fd1498Szrj 	  else if (op0_sign == op1_sign)
1716*38fd1498Szrj 	    {
1717*38fd1498Szrj 	      smaller_sign = op0_sign;
1718*38fd1498Szrj 	      larger_sign = op0_sign;
1719*38fd1498Szrj 	    }
1720*38fd1498Szrj 
1721*38fd1498Szrj 	  if (!op0_small_p)
1722*38fd1498Szrj 	    do_compare_rtx_and_jump (signbit0, hipart0, NE, true, hmode,
1723*38fd1498Szrj 				     NULL_RTX, NULL, large_op0,
1724*38fd1498Szrj 				     profile_probability::unlikely ());
1725*38fd1498Szrj 
1726*38fd1498Szrj 	  if (!op1_small_p)
1727*38fd1498Szrj 	    do_compare_rtx_and_jump (signbit1, hipart1, NE, true, hmode,
1728*38fd1498Szrj 				     NULL_RTX, NULL, small_op0_large_op1,
1729*38fd1498Szrj 				     profile_probability::unlikely ());
1730*38fd1498Szrj 
1731*38fd1498Szrj 	  /* If both op0 and op1 are sign (!uns) or zero (uns) extended from
1732*38fd1498Szrj 	     hmode to mode, the multiplication will never overflow.  We can
1733*38fd1498Szrj 	     do just one hmode x hmode => mode widening multiplication.  */
1734*38fd1498Szrj 	  rtx lopart0s = lopart0, lopart1s = lopart1;
1735*38fd1498Szrj 	  if (GET_CODE (lopart0) == SUBREG)
1736*38fd1498Szrj 	    {
1737*38fd1498Szrj 	      lopart0s = shallow_copy_rtx (lopart0);
1738*38fd1498Szrj 	      SUBREG_PROMOTED_VAR_P (lopart0s) = 1;
1739*38fd1498Szrj 	      SUBREG_PROMOTED_SET (lopart0s, uns ? SRP_UNSIGNED : SRP_SIGNED);
1740*38fd1498Szrj 	    }
1741*38fd1498Szrj 	  if (GET_CODE (lopart1) == SUBREG)
1742*38fd1498Szrj 	    {
1743*38fd1498Szrj 	      lopart1s = shallow_copy_rtx (lopart1);
1744*38fd1498Szrj 	      SUBREG_PROMOTED_VAR_P (lopart1s) = 1;
1745*38fd1498Szrj 	      SUBREG_PROMOTED_SET (lopart1s, uns ? SRP_UNSIGNED : SRP_SIGNED);
1746*38fd1498Szrj 	    }
1747*38fd1498Szrj 	  tree halfstype = build_nonstandard_integer_type (hprec, uns);
1748*38fd1498Szrj 	  ops.op0 = make_tree (halfstype, lopart0s);
1749*38fd1498Szrj 	  ops.op1 = make_tree (halfstype, lopart1s);
1750*38fd1498Szrj 	  ops.code = WIDEN_MULT_EXPR;
1751*38fd1498Szrj 	  ops.type = type;
1752*38fd1498Szrj 	  rtx thisres
1753*38fd1498Szrj 	    = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1754*38fd1498Szrj 	  emit_move_insn (res, thisres);
1755*38fd1498Szrj 	  emit_jump (done_label);
1756*38fd1498Szrj 
1757*38fd1498Szrj 	  emit_label (small_op0_large_op1);
1758*38fd1498Szrj 
1759*38fd1498Szrj 	  /* If op0 is sign (!uns) or zero (uns) extended from hmode to mode,
1760*38fd1498Szrj 	     but op1 is not, just swap the arguments and handle it as op1
1761*38fd1498Szrj 	     sign/zero extended, op0 not.  */
1762*38fd1498Szrj 	  rtx larger = gen_reg_rtx (mode);
1763*38fd1498Szrj 	  rtx hipart = gen_reg_rtx (hmode);
1764*38fd1498Szrj 	  rtx lopart = gen_reg_rtx (hmode);
1765*38fd1498Szrj 	  emit_move_insn (larger, op1);
1766*38fd1498Szrj 	  emit_move_insn (hipart, hipart1);
1767*38fd1498Szrj 	  emit_move_insn (lopart, lopart0);
1768*38fd1498Szrj 	  emit_jump (one_small_one_large);
1769*38fd1498Szrj 
1770*38fd1498Szrj 	  emit_label (large_op0);
1771*38fd1498Szrj 
1772*38fd1498Szrj 	  if (!op1_small_p)
1773*38fd1498Szrj 	    do_compare_rtx_and_jump (signbit1, hipart1, NE, true, hmode,
1774*38fd1498Szrj 				     NULL_RTX, NULL, both_ops_large,
1775*38fd1498Szrj 				     profile_probability::unlikely ());
1776*38fd1498Szrj 
1777*38fd1498Szrj 	  /* If op1 is sign (!uns) or zero (uns) extended from hmode to mode,
1778*38fd1498Szrj 	     but op0 is not, prepare larger, hipart and lopart pseudos and
1779*38fd1498Szrj 	     handle it together with small_op0_large_op1.  */
1780*38fd1498Szrj 	  emit_move_insn (larger, op0);
1781*38fd1498Szrj 	  emit_move_insn (hipart, hipart0);
1782*38fd1498Szrj 	  emit_move_insn (lopart, lopart1);
1783*38fd1498Szrj 
1784*38fd1498Szrj 	  emit_label (one_small_one_large);
1785*38fd1498Szrj 
1786*38fd1498Szrj 	  /* lopart is the low part of the operand that is sign extended
1787*38fd1498Szrj 	     to mode, larger is the other operand, hipart is the
1788*38fd1498Szrj 	     high part of larger and lopart0 and lopart1 are the low parts
1789*38fd1498Szrj 	     of both operands.
1790*38fd1498Szrj 	     We perform lopart0 * lopart1 and lopart * hipart widening
1791*38fd1498Szrj 	     multiplications.  */
1792*38fd1498Szrj 	  tree halfutype = build_nonstandard_integer_type (hprec, 1);
1793*38fd1498Szrj 	  ops.op0 = make_tree (halfutype, lopart0);
1794*38fd1498Szrj 	  ops.op1 = make_tree (halfutype, lopart1);
1795*38fd1498Szrj 	  rtx lo0xlo1
1796*38fd1498Szrj 	    = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1797*38fd1498Szrj 
1798*38fd1498Szrj 	  ops.op0 = make_tree (halfutype, lopart);
1799*38fd1498Szrj 	  ops.op1 = make_tree (halfutype, hipart);
1800*38fd1498Szrj 	  rtx loxhi = gen_reg_rtx (mode);
1801*38fd1498Szrj 	  rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1802*38fd1498Szrj 	  emit_move_insn (loxhi, tem);
1803*38fd1498Szrj 
1804*38fd1498Szrj 	  if (!uns)
1805*38fd1498Szrj 	    {
1806*38fd1498Szrj 	      /* if (hipart < 0) loxhi -= lopart << (bitsize / 2);  */
1807*38fd1498Szrj 	      if (larger_sign == 0)
1808*38fd1498Szrj 		emit_jump (after_hipart_neg);
1809*38fd1498Szrj 	      else if (larger_sign != -1)
1810*38fd1498Szrj 		do_compare_rtx_and_jump (hipart, const0_rtx, GE, false, hmode,
1811*38fd1498Szrj 					 NULL_RTX, NULL, after_hipart_neg,
1812*38fd1498Szrj 					 profile_probability::even ());
1813*38fd1498Szrj 
1814*38fd1498Szrj 	      tem = convert_modes (mode, hmode, lopart, 1);
1815*38fd1498Szrj 	      tem = expand_shift (LSHIFT_EXPR, mode, tem, hprec, NULL_RTX, 1);
1816*38fd1498Szrj 	      tem = expand_simple_binop (mode, MINUS, loxhi, tem, NULL_RTX,
1817*38fd1498Szrj 					 1, OPTAB_WIDEN);
1818*38fd1498Szrj 	      emit_move_insn (loxhi, tem);
1819*38fd1498Szrj 
1820*38fd1498Szrj 	      emit_label (after_hipart_neg);
1821*38fd1498Szrj 
1822*38fd1498Szrj 	      /* if (lopart < 0) loxhi -= larger;  */
1823*38fd1498Szrj 	      if (smaller_sign == 0)
1824*38fd1498Szrj 		emit_jump (after_lopart_neg);
1825*38fd1498Szrj 	      else if (smaller_sign != -1)
1826*38fd1498Szrj 		do_compare_rtx_and_jump (lopart, const0_rtx, GE, false, hmode,
1827*38fd1498Szrj 					 NULL_RTX, NULL, after_lopart_neg,
1828*38fd1498Szrj 					 profile_probability::even ());
1829*38fd1498Szrj 
1830*38fd1498Szrj 	      tem = expand_simple_binop (mode, MINUS, loxhi, larger, NULL_RTX,
1831*38fd1498Szrj 					 1, OPTAB_WIDEN);
1832*38fd1498Szrj 	      emit_move_insn (loxhi, tem);
1833*38fd1498Szrj 
1834*38fd1498Szrj 	      emit_label (after_lopart_neg);
1835*38fd1498Szrj 	    }
1836*38fd1498Szrj 
1837*38fd1498Szrj 	  /* loxhi += (uns) lo0xlo1 >> (bitsize / 2);  */
1838*38fd1498Szrj 	  tem = expand_shift (RSHIFT_EXPR, mode, lo0xlo1, hprec, NULL_RTX, 1);
1839*38fd1498Szrj 	  tem = expand_simple_binop (mode, PLUS, loxhi, tem, NULL_RTX,
1840*38fd1498Szrj 				     1, OPTAB_WIDEN);
1841*38fd1498Szrj 	  emit_move_insn (loxhi, tem);
1842*38fd1498Szrj 
1843*38fd1498Szrj 	  /* if (loxhi >> (bitsize / 2)
1844*38fd1498Szrj 		 == (hmode) loxhi >> (bitsize / 2 - 1))  (if !uns)
1845*38fd1498Szrj 	     if (loxhi >> (bitsize / 2) == 0		 (if uns).  */
1846*38fd1498Szrj 	  rtx hipartloxhi = expand_shift (RSHIFT_EXPR, mode, loxhi, hprec,
1847*38fd1498Szrj 					  NULL_RTX, 0);
1848*38fd1498Szrj 	  hipartloxhi = convert_modes (hmode, mode, hipartloxhi, 0);
1849*38fd1498Szrj 	  rtx signbitloxhi = const0_rtx;
1850*38fd1498Szrj 	  if (!uns)
1851*38fd1498Szrj 	    signbitloxhi = expand_shift (RSHIFT_EXPR, hmode,
1852*38fd1498Szrj 					 convert_modes (hmode, mode,
1853*38fd1498Szrj 							loxhi, 0),
1854*38fd1498Szrj 					 hprec - 1, NULL_RTX, 0);
1855*38fd1498Szrj 
1856*38fd1498Szrj 	  do_compare_rtx_and_jump (signbitloxhi, hipartloxhi, NE, true, hmode,
1857*38fd1498Szrj 				   NULL_RTX, NULL, do_overflow,
1858*38fd1498Szrj 				   profile_probability::very_unlikely ());
1859*38fd1498Szrj 
1860*38fd1498Szrj 	  /* res = (loxhi << (bitsize / 2)) | (hmode) lo0xlo1;  */
1861*38fd1498Szrj 	  rtx loxhishifted = expand_shift (LSHIFT_EXPR, mode, loxhi, hprec,
1862*38fd1498Szrj 					   NULL_RTX, 1);
1863*38fd1498Szrj 	  tem = convert_modes (mode, hmode,
1864*38fd1498Szrj 			       convert_modes (hmode, mode, lo0xlo1, 1), 1);
1865*38fd1498Szrj 
1866*38fd1498Szrj 	  tem = expand_simple_binop (mode, IOR, loxhishifted, tem, res,
1867*38fd1498Szrj 				     1, OPTAB_WIDEN);
1868*38fd1498Szrj 	  if (tem != res)
1869*38fd1498Szrj 	    emit_move_insn (res, tem);
1870*38fd1498Szrj 	  emit_jump (done_label);
1871*38fd1498Szrj 
1872*38fd1498Szrj 	  emit_label (both_ops_large);
1873*38fd1498Szrj 
1874*38fd1498Szrj 	  /* If both operands are large (not sign (!uns) or zero (uns)
1875*38fd1498Szrj 	     extended from hmode), then perform the full multiplication
1876*38fd1498Szrj 	     which will be the result of the operation.
1877*38fd1498Szrj 	     The only cases which don't overflow are for signed multiplication
1878*38fd1498Szrj 	     some cases where both hipart0 and highpart1 are 0 or -1.
1879*38fd1498Szrj 	     For unsigned multiplication when high parts are both non-zero
1880*38fd1498Szrj 	     this overflows always.  */
1881*38fd1498Szrj 	  ops.code = MULT_EXPR;
1882*38fd1498Szrj 	  ops.op0 = make_tree (type, op0);
1883*38fd1498Szrj 	  ops.op1 = make_tree (type, op1);
1884*38fd1498Szrj 	  tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1885*38fd1498Szrj 	  emit_move_insn (res, tem);
1886*38fd1498Szrj 
1887*38fd1498Szrj 	  if (!uns)
1888*38fd1498Szrj 	    {
1889*38fd1498Szrj 	      if (!op0_medium_p)
1890*38fd1498Szrj 		{
1891*38fd1498Szrj 		  tem = expand_simple_binop (hmode, PLUS, hipart0, const1_rtx,
1892*38fd1498Szrj 					     NULL_RTX, 1, OPTAB_WIDEN);
1893*38fd1498Szrj 		  do_compare_rtx_and_jump (tem, const1_rtx, GTU, true, hmode,
1894*38fd1498Szrj 					   NULL_RTX, NULL, do_error,
1895*38fd1498Szrj 					   profile_probability::very_unlikely ());
1896*38fd1498Szrj 		}
1897*38fd1498Szrj 
1898*38fd1498Szrj 	      if (!op1_medium_p)
1899*38fd1498Szrj 		{
1900*38fd1498Szrj 		  tem = expand_simple_binop (hmode, PLUS, hipart1, const1_rtx,
1901*38fd1498Szrj 					     NULL_RTX, 1, OPTAB_WIDEN);
1902*38fd1498Szrj 		  do_compare_rtx_and_jump (tem, const1_rtx, GTU, true, hmode,
1903*38fd1498Szrj 					   NULL_RTX, NULL, do_error,
1904*38fd1498Szrj 					   profile_probability::very_unlikely ());
1905*38fd1498Szrj 		}
1906*38fd1498Szrj 
1907*38fd1498Szrj 	      /* At this point hipart{0,1} are both in [-1, 0].  If they are
1908*38fd1498Szrj 		 the same, overflow happened if res is non-positive, if they
1909*38fd1498Szrj 		 are different, overflow happened if res is positive.  */
1910*38fd1498Szrj 	      if (op0_sign != 1 && op1_sign != 1 && op0_sign != op1_sign)
1911*38fd1498Szrj 		emit_jump (hipart_different);
1912*38fd1498Szrj 	      else if (op0_sign == 1 || op1_sign == 1)
1913*38fd1498Szrj 		do_compare_rtx_and_jump (hipart0, hipart1, NE, true, hmode,
1914*38fd1498Szrj 					 NULL_RTX, NULL, hipart_different,
1915*38fd1498Szrj 					 profile_probability::even ());
1916*38fd1498Szrj 
1917*38fd1498Szrj 	      do_compare_rtx_and_jump (res, const0_rtx, LE, false, mode,
1918*38fd1498Szrj 				       NULL_RTX, NULL, do_error,
1919*38fd1498Szrj 				       profile_probability::very_unlikely ());
1920*38fd1498Szrj 	      emit_jump (done_label);
1921*38fd1498Szrj 
1922*38fd1498Szrj 	      emit_label (hipart_different);
1923*38fd1498Szrj 
1924*38fd1498Szrj 	      do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode,
1925*38fd1498Szrj 				       NULL_RTX, NULL, do_error,
1926*38fd1498Szrj 				       profile_probability::very_unlikely ());
1927*38fd1498Szrj 	      emit_jump (done_label);
1928*38fd1498Szrj 	    }
1929*38fd1498Szrj 
1930*38fd1498Szrj 	  emit_label (do_overflow);
1931*38fd1498Szrj 
1932*38fd1498Szrj 	  /* Overflow, do full multiplication and fallthru into do_error.  */
1933*38fd1498Szrj 	  ops.op0 = make_tree (type, op0);
1934*38fd1498Szrj 	  ops.op1 = make_tree (type, op1);
1935*38fd1498Szrj 	  tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1936*38fd1498Szrj 	  emit_move_insn (res, tem);
1937*38fd1498Szrj 	}
1938*38fd1498Szrj       else if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
1939*38fd1498Szrj 	       && targetm.scalar_mode_supported_p (wmode))
1940*38fd1498Szrj 	/* Even emitting a libcall is better than not detecting overflow
1941*38fd1498Szrj 	   at all.  */
1942*38fd1498Szrj 	goto twoxwider;
1943*38fd1498Szrj       else
1944*38fd1498Szrj 	{
1945*38fd1498Szrj 	  gcc_assert (!is_ubsan);
1946*38fd1498Szrj 	  ops.code = MULT_EXPR;
1947*38fd1498Szrj 	  ops.type = type;
1948*38fd1498Szrj 	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1949*38fd1498Szrj 	  emit_jump (done_label);
1950*38fd1498Szrj 	}
1951*38fd1498Szrj     }
1952*38fd1498Szrj 
1953*38fd1498Szrj  do_error_label:
1954*38fd1498Szrj   emit_label (do_error);
1955*38fd1498Szrj   if (is_ubsan)
1956*38fd1498Szrj     {
1957*38fd1498Szrj       /* Expand the ubsan builtin call.  */
1958*38fd1498Szrj       push_temp_slots ();
1959*38fd1498Szrj       fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (arg0),
1960*38fd1498Szrj 					 arg0, arg1, datap);
1961*38fd1498Szrj       expand_normal (fn);
1962*38fd1498Szrj       pop_temp_slots ();
1963*38fd1498Szrj       do_pending_stack_adjust ();
1964*38fd1498Szrj     }
1965*38fd1498Szrj   else if (lhs)
1966*38fd1498Szrj     expand_arith_set_overflow (lhs, target);
1967*38fd1498Szrj 
1968*38fd1498Szrj   /* We're done.  */
1969*38fd1498Szrj   emit_label (done_label);
1970*38fd1498Szrj 
1971*38fd1498Szrj   /* u1 * u2 -> sr  */
1972*38fd1498Szrj   if (uns0_p && uns1_p && !unsr_p)
1973*38fd1498Szrj     {
1974*38fd1498Szrj       rtx_code_label *all_done_label = gen_label_rtx ();
1975*38fd1498Szrj       do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
1976*38fd1498Szrj 			       NULL, all_done_label, profile_probability::very_likely ());
1977*38fd1498Szrj       expand_arith_set_overflow (lhs, target);
1978*38fd1498Szrj       emit_label (all_done_label);
1979*38fd1498Szrj     }
1980*38fd1498Szrj 
1981*38fd1498Szrj   /* s1 * u2 -> sr  */
1982*38fd1498Szrj   if (!uns0_p && uns1_p && !unsr_p && pos_neg1 == 3)
1983*38fd1498Szrj     {
1984*38fd1498Szrj       rtx_code_label *all_done_label = gen_label_rtx ();
1985*38fd1498Szrj       rtx_code_label *set_noovf = gen_label_rtx ();
1986*38fd1498Szrj       do_compare_rtx_and_jump (op1, const0_rtx, GE, false, mode, NULL_RTX,
1987*38fd1498Szrj 			       NULL, all_done_label, profile_probability::very_likely ());
1988*38fd1498Szrj       expand_arith_set_overflow (lhs, target);
1989*38fd1498Szrj       do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
1990*38fd1498Szrj 			       NULL, set_noovf, profile_probability::very_likely ());
1991*38fd1498Szrj       do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
1992*38fd1498Szrj 			       NULL, all_done_label, profile_probability::very_unlikely ());
1993*38fd1498Szrj       do_compare_rtx_and_jump (op1, res, NE, true, mode, NULL_RTX, NULL,
1994*38fd1498Szrj 			       all_done_label, profile_probability::very_unlikely ());
1995*38fd1498Szrj       emit_label (set_noovf);
1996*38fd1498Szrj       write_complex_part (target, const0_rtx, true);
1997*38fd1498Szrj       emit_label (all_done_label);
1998*38fd1498Szrj     }
1999*38fd1498Szrj 
2000*38fd1498Szrj   if (lhs)
2001*38fd1498Szrj     {
2002*38fd1498Szrj       if (is_ubsan)
2003*38fd1498Szrj 	expand_ubsan_result_store (target, res);
2004*38fd1498Szrj       else
2005*38fd1498Szrj 	expand_arith_overflow_result_store (lhs, target, mode, res);
2006*38fd1498Szrj     }
2007*38fd1498Szrj }
2008*38fd1498Szrj 
2009*38fd1498Szrj /* Expand UBSAN_CHECK_* internal function if it has vector operands.  */
2010*38fd1498Szrj 
2011*38fd1498Szrj static void
expand_vector_ubsan_overflow(location_t loc,enum tree_code code,tree lhs,tree arg0,tree arg1)2012*38fd1498Szrj expand_vector_ubsan_overflow (location_t loc, enum tree_code code, tree lhs,
2013*38fd1498Szrj 			      tree arg0, tree arg1)
2014*38fd1498Szrj {
2015*38fd1498Szrj   poly_uint64 cnt = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0));
2016*38fd1498Szrj   rtx_code_label *loop_lab = NULL;
2017*38fd1498Szrj   rtx cntvar = NULL_RTX;
2018*38fd1498Szrj   tree cntv = NULL_TREE;
2019*38fd1498Szrj   tree eltype = TREE_TYPE (TREE_TYPE (arg0));
2020*38fd1498Szrj   tree sz = TYPE_SIZE (eltype);
2021*38fd1498Szrj   tree data = NULL_TREE;
2022*38fd1498Szrj   tree resv = NULL_TREE;
2023*38fd1498Szrj   rtx lhsr = NULL_RTX;
2024*38fd1498Szrj   rtx resvr = NULL_RTX;
2025*38fd1498Szrj   unsigned HOST_WIDE_INT const_cnt = 0;
2026*38fd1498Szrj   bool use_loop_p = (!cnt.is_constant (&const_cnt) || const_cnt > 4);
2027*38fd1498Szrj 
2028*38fd1498Szrj   if (lhs)
2029*38fd1498Szrj     {
2030*38fd1498Szrj       optab op;
2031*38fd1498Szrj       lhsr = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2032*38fd1498Szrj       if (!VECTOR_MODE_P (GET_MODE (lhsr))
2033*38fd1498Szrj 	  || (op = optab_for_tree_code (code, TREE_TYPE (arg0),
2034*38fd1498Szrj 					optab_default)) == unknown_optab
2035*38fd1498Szrj 	  || (optab_handler (op, TYPE_MODE (TREE_TYPE (arg0)))
2036*38fd1498Szrj 	      == CODE_FOR_nothing))
2037*38fd1498Szrj 	{
2038*38fd1498Szrj 	  if (MEM_P (lhsr))
2039*38fd1498Szrj 	    resv = make_tree (TREE_TYPE (lhs), lhsr);
2040*38fd1498Szrj 	  else
2041*38fd1498Szrj 	    {
2042*38fd1498Szrj 	      resvr = assign_temp (TREE_TYPE (lhs), 1, 1);
2043*38fd1498Szrj 	      resv = make_tree (TREE_TYPE (lhs), resvr);
2044*38fd1498Szrj 	    }
2045*38fd1498Szrj 	}
2046*38fd1498Szrj     }
2047*38fd1498Szrj   if (use_loop_p)
2048*38fd1498Szrj     {
2049*38fd1498Szrj       do_pending_stack_adjust ();
2050*38fd1498Szrj       loop_lab = gen_label_rtx ();
2051*38fd1498Szrj       cntvar = gen_reg_rtx (TYPE_MODE (sizetype));
2052*38fd1498Szrj       cntv = make_tree (sizetype, cntvar);
2053*38fd1498Szrj       emit_move_insn (cntvar, const0_rtx);
2054*38fd1498Szrj       emit_label (loop_lab);
2055*38fd1498Szrj     }
2056*38fd1498Szrj   if (TREE_CODE (arg0) != VECTOR_CST)
2057*38fd1498Szrj     {
2058*38fd1498Szrj       rtx arg0r = expand_normal (arg0);
2059*38fd1498Szrj       arg0 = make_tree (TREE_TYPE (arg0), arg0r);
2060*38fd1498Szrj     }
2061*38fd1498Szrj   if (TREE_CODE (arg1) != VECTOR_CST)
2062*38fd1498Szrj     {
2063*38fd1498Szrj       rtx arg1r = expand_normal (arg1);
2064*38fd1498Szrj       arg1 = make_tree (TREE_TYPE (arg1), arg1r);
2065*38fd1498Szrj     }
2066*38fd1498Szrj   for (unsigned int i = 0; i < (use_loop_p ? 1 : const_cnt); i++)
2067*38fd1498Szrj     {
2068*38fd1498Szrj       tree op0, op1, res = NULL_TREE;
2069*38fd1498Szrj       if (use_loop_p)
2070*38fd1498Szrj 	{
2071*38fd1498Szrj 	  tree atype = build_array_type_nelts (eltype, cnt);
2072*38fd1498Szrj 	  op0 = uniform_vector_p (arg0);
2073*38fd1498Szrj 	  if (op0 == NULL_TREE)
2074*38fd1498Szrj 	    {
2075*38fd1498Szrj 	      op0 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg0);
2076*38fd1498Szrj 	      op0 = build4_loc (loc, ARRAY_REF, eltype, op0, cntv,
2077*38fd1498Szrj 				NULL_TREE, NULL_TREE);
2078*38fd1498Szrj 	    }
2079*38fd1498Szrj 	  op1 = uniform_vector_p (arg1);
2080*38fd1498Szrj 	  if (op1 == NULL_TREE)
2081*38fd1498Szrj 	    {
2082*38fd1498Szrj 	      op1 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg1);
2083*38fd1498Szrj 	      op1 = build4_loc (loc, ARRAY_REF, eltype, op1, cntv,
2084*38fd1498Szrj 				NULL_TREE, NULL_TREE);
2085*38fd1498Szrj 	    }
2086*38fd1498Szrj 	  if (resv)
2087*38fd1498Szrj 	    {
2088*38fd1498Szrj 	      res = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, resv);
2089*38fd1498Szrj 	      res = build4_loc (loc, ARRAY_REF, eltype, res, cntv,
2090*38fd1498Szrj 				NULL_TREE, NULL_TREE);
2091*38fd1498Szrj 	    }
2092*38fd1498Szrj 	}
2093*38fd1498Szrj       else
2094*38fd1498Szrj 	{
2095*38fd1498Szrj 	  tree bitpos = bitsize_int (tree_to_uhwi (sz) * i);
2096*38fd1498Szrj 	  op0 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg0, sz, bitpos);
2097*38fd1498Szrj 	  op1 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg1, sz, bitpos);
2098*38fd1498Szrj 	  if (resv)
2099*38fd1498Szrj 	    res = fold_build3_loc (loc, BIT_FIELD_REF, eltype, resv, sz,
2100*38fd1498Szrj 				   bitpos);
2101*38fd1498Szrj 	}
2102*38fd1498Szrj       switch (code)
2103*38fd1498Szrj 	{
2104*38fd1498Szrj 	case PLUS_EXPR:
2105*38fd1498Szrj 	  expand_addsub_overflow (loc, PLUS_EXPR, res, op0, op1,
2106*38fd1498Szrj 				  false, false, false, true, &data);
2107*38fd1498Szrj 	  break;
2108*38fd1498Szrj 	case MINUS_EXPR:
2109*38fd1498Szrj 	  if (use_loop_p ? integer_zerop (arg0) : integer_zerop (op0))
2110*38fd1498Szrj 	    expand_neg_overflow (loc, res, op1, true, &data);
2111*38fd1498Szrj 	  else
2112*38fd1498Szrj 	    expand_addsub_overflow (loc, MINUS_EXPR, res, op0, op1,
2113*38fd1498Szrj 				    false, false, false, true, &data);
2114*38fd1498Szrj 	  break;
2115*38fd1498Szrj 	case MULT_EXPR:
2116*38fd1498Szrj 	  expand_mul_overflow (loc, res, op0, op1, false, false, false,
2117*38fd1498Szrj 			       true, &data);
2118*38fd1498Szrj 	  break;
2119*38fd1498Szrj 	default:
2120*38fd1498Szrj 	  gcc_unreachable ();
2121*38fd1498Szrj 	}
2122*38fd1498Szrj     }
2123*38fd1498Szrj   if (use_loop_p)
2124*38fd1498Szrj     {
2125*38fd1498Szrj       struct separate_ops ops;
2126*38fd1498Szrj       ops.code = PLUS_EXPR;
2127*38fd1498Szrj       ops.type = TREE_TYPE (cntv);
2128*38fd1498Szrj       ops.op0 = cntv;
2129*38fd1498Szrj       ops.op1 = build_int_cst (TREE_TYPE (cntv), 1);
2130*38fd1498Szrj       ops.op2 = NULL_TREE;
2131*38fd1498Szrj       ops.location = loc;
2132*38fd1498Szrj       rtx ret = expand_expr_real_2 (&ops, cntvar, TYPE_MODE (sizetype),
2133*38fd1498Szrj 				    EXPAND_NORMAL);
2134*38fd1498Szrj       if (ret != cntvar)
2135*38fd1498Szrj 	emit_move_insn (cntvar, ret);
2136*38fd1498Szrj       rtx cntrtx = gen_int_mode (cnt, TYPE_MODE (sizetype));
2137*38fd1498Szrj       do_compare_rtx_and_jump (cntvar, cntrtx, NE, false,
2138*38fd1498Szrj 			       TYPE_MODE (sizetype), NULL_RTX, NULL, loop_lab,
2139*38fd1498Szrj 			       profile_probability::very_likely ());
2140*38fd1498Szrj     }
2141*38fd1498Szrj   if (lhs && resv == NULL_TREE)
2142*38fd1498Szrj     {
2143*38fd1498Szrj       struct separate_ops ops;
2144*38fd1498Szrj       ops.code = code;
2145*38fd1498Szrj       ops.type = TREE_TYPE (arg0);
2146*38fd1498Szrj       ops.op0 = arg0;
2147*38fd1498Szrj       ops.op1 = arg1;
2148*38fd1498Szrj       ops.op2 = NULL_TREE;
2149*38fd1498Szrj       ops.location = loc;
2150*38fd1498Szrj       rtx ret = expand_expr_real_2 (&ops, lhsr, TYPE_MODE (TREE_TYPE (arg0)),
2151*38fd1498Szrj 				    EXPAND_NORMAL);
2152*38fd1498Szrj       if (ret != lhsr)
2153*38fd1498Szrj 	emit_move_insn (lhsr, ret);
2154*38fd1498Szrj     }
2155*38fd1498Szrj   else if (resvr)
2156*38fd1498Szrj     emit_move_insn (lhsr, resvr);
2157*38fd1498Szrj }
2158*38fd1498Szrj 
2159*38fd1498Szrj /* Expand UBSAN_CHECK_ADD call STMT.  */
2160*38fd1498Szrj 
2161*38fd1498Szrj static void
expand_UBSAN_CHECK_ADD(internal_fn,gcall * stmt)2162*38fd1498Szrj expand_UBSAN_CHECK_ADD (internal_fn, gcall *stmt)
2163*38fd1498Szrj {
2164*38fd1498Szrj   location_t loc = gimple_location (stmt);
2165*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
2166*38fd1498Szrj   tree arg0 = gimple_call_arg (stmt, 0);
2167*38fd1498Szrj   tree arg1 = gimple_call_arg (stmt, 1);
2168*38fd1498Szrj   if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
2169*38fd1498Szrj     expand_vector_ubsan_overflow (loc, PLUS_EXPR, lhs, arg0, arg1);
2170*38fd1498Szrj   else
2171*38fd1498Szrj     expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1,
2172*38fd1498Szrj 			    false, false, false, true, NULL);
2173*38fd1498Szrj }
2174*38fd1498Szrj 
2175*38fd1498Szrj /* Expand UBSAN_CHECK_SUB call STMT.  */
2176*38fd1498Szrj 
2177*38fd1498Szrj static void
expand_UBSAN_CHECK_SUB(internal_fn,gcall * stmt)2178*38fd1498Szrj expand_UBSAN_CHECK_SUB (internal_fn, gcall *stmt)
2179*38fd1498Szrj {
2180*38fd1498Szrj   location_t loc = gimple_location (stmt);
2181*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
2182*38fd1498Szrj   tree arg0 = gimple_call_arg (stmt, 0);
2183*38fd1498Szrj   tree arg1 = gimple_call_arg (stmt, 1);
2184*38fd1498Szrj   if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
2185*38fd1498Szrj     expand_vector_ubsan_overflow (loc, MINUS_EXPR, lhs, arg0, arg1);
2186*38fd1498Szrj   else if (integer_zerop (arg0))
2187*38fd1498Szrj     expand_neg_overflow (loc, lhs, arg1, true, NULL);
2188*38fd1498Szrj   else
2189*38fd1498Szrj     expand_addsub_overflow (loc, MINUS_EXPR, lhs, arg0, arg1,
2190*38fd1498Szrj 			    false, false, false, true, NULL);
2191*38fd1498Szrj }
2192*38fd1498Szrj 
2193*38fd1498Szrj /* Expand UBSAN_CHECK_MUL call STMT.  */
2194*38fd1498Szrj 
2195*38fd1498Szrj static void
expand_UBSAN_CHECK_MUL(internal_fn,gcall * stmt)2196*38fd1498Szrj expand_UBSAN_CHECK_MUL (internal_fn, gcall *stmt)
2197*38fd1498Szrj {
2198*38fd1498Szrj   location_t loc = gimple_location (stmt);
2199*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
2200*38fd1498Szrj   tree arg0 = gimple_call_arg (stmt, 0);
2201*38fd1498Szrj   tree arg1 = gimple_call_arg (stmt, 1);
2202*38fd1498Szrj   if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
2203*38fd1498Szrj     expand_vector_ubsan_overflow (loc, MULT_EXPR, lhs, arg0, arg1);
2204*38fd1498Szrj   else
2205*38fd1498Szrj     expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true,
2206*38fd1498Szrj 			 NULL);
2207*38fd1498Szrj }
2208*38fd1498Szrj 
2209*38fd1498Szrj /* Helper function for {ADD,SUB,MUL}_OVERFLOW call stmt expansion.  */
2210*38fd1498Szrj 
2211*38fd1498Szrj static void
expand_arith_overflow(enum tree_code code,gimple * stmt)2212*38fd1498Szrj expand_arith_overflow (enum tree_code code, gimple *stmt)
2213*38fd1498Szrj {
2214*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
2215*38fd1498Szrj   if (lhs == NULL_TREE)
2216*38fd1498Szrj     return;
2217*38fd1498Szrj   tree arg0 = gimple_call_arg (stmt, 0);
2218*38fd1498Szrj   tree arg1 = gimple_call_arg (stmt, 1);
2219*38fd1498Szrj   tree type = TREE_TYPE (TREE_TYPE (lhs));
2220*38fd1498Szrj   int uns0_p = TYPE_UNSIGNED (TREE_TYPE (arg0));
2221*38fd1498Szrj   int uns1_p = TYPE_UNSIGNED (TREE_TYPE (arg1));
2222*38fd1498Szrj   int unsr_p = TYPE_UNSIGNED (type);
2223*38fd1498Szrj   int prec0 = TYPE_PRECISION (TREE_TYPE (arg0));
2224*38fd1498Szrj   int prec1 = TYPE_PRECISION (TREE_TYPE (arg1));
2225*38fd1498Szrj   int precres = TYPE_PRECISION (type);
2226*38fd1498Szrj   location_t loc = gimple_location (stmt);
2227*38fd1498Szrj   if (!uns0_p && get_range_pos_neg (arg0) == 1)
2228*38fd1498Szrj     uns0_p = true;
2229*38fd1498Szrj   if (!uns1_p && get_range_pos_neg (arg1) == 1)
2230*38fd1498Szrj     uns1_p = true;
2231*38fd1498Szrj   int pr = get_min_precision (arg0, uns0_p ? UNSIGNED : SIGNED);
2232*38fd1498Szrj   prec0 = MIN (prec0, pr);
2233*38fd1498Szrj   pr = get_min_precision (arg1, uns1_p ? UNSIGNED : SIGNED);
2234*38fd1498Szrj   prec1 = MIN (prec1, pr);
2235*38fd1498Szrj 
2236*38fd1498Szrj   /* If uns0_p && uns1_p, precop is minimum needed precision
2237*38fd1498Szrj      of unsigned type to hold the exact result, otherwise
2238*38fd1498Szrj      precop is minimum needed precision of signed type to
2239*38fd1498Szrj      hold the exact result.  */
2240*38fd1498Szrj   int precop;
2241*38fd1498Szrj   if (code == MULT_EXPR)
2242*38fd1498Szrj     precop = prec0 + prec1 + (uns0_p != uns1_p);
2243*38fd1498Szrj   else
2244*38fd1498Szrj     {
2245*38fd1498Szrj       if (uns0_p == uns1_p)
2246*38fd1498Szrj 	precop = MAX (prec0, prec1) + 1;
2247*38fd1498Szrj       else if (uns0_p)
2248*38fd1498Szrj 	precop = MAX (prec0 + 1, prec1) + 1;
2249*38fd1498Szrj       else
2250*38fd1498Szrj 	precop = MAX (prec0, prec1 + 1) + 1;
2251*38fd1498Szrj     }
2252*38fd1498Szrj   int orig_precres = precres;
2253*38fd1498Szrj 
2254*38fd1498Szrj   do
2255*38fd1498Szrj     {
2256*38fd1498Szrj       if ((uns0_p && uns1_p)
2257*38fd1498Szrj 	  ? ((precop + !unsr_p) <= precres
2258*38fd1498Szrj 	     /* u1 - u2 -> ur can overflow, no matter what precision
2259*38fd1498Szrj 		the result has.  */
2260*38fd1498Szrj 	     && (code != MINUS_EXPR || !unsr_p))
2261*38fd1498Szrj 	  : (!unsr_p && precop <= precres))
2262*38fd1498Szrj 	{
2263*38fd1498Szrj 	  /* The infinity precision result will always fit into result.  */
2264*38fd1498Szrj 	  rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2265*38fd1498Szrj 	  write_complex_part (target, const0_rtx, true);
2266*38fd1498Szrj 	  scalar_int_mode mode = SCALAR_INT_TYPE_MODE (type);
2267*38fd1498Szrj 	  struct separate_ops ops;
2268*38fd1498Szrj 	  ops.code = code;
2269*38fd1498Szrj 	  ops.type = type;
2270*38fd1498Szrj 	  ops.op0 = fold_convert_loc (loc, type, arg0);
2271*38fd1498Szrj 	  ops.op1 = fold_convert_loc (loc, type, arg1);
2272*38fd1498Szrj 	  ops.op2 = NULL_TREE;
2273*38fd1498Szrj 	  ops.location = loc;
2274*38fd1498Szrj 	  rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2275*38fd1498Szrj 	  expand_arith_overflow_result_store (lhs, target, mode, tem);
2276*38fd1498Szrj 	  return;
2277*38fd1498Szrj 	}
2278*38fd1498Szrj 
2279*38fd1498Szrj       /* For operations with low precision, if target doesn't have them, start
2280*38fd1498Szrj 	 with precres widening right away, otherwise do it only if the most
2281*38fd1498Szrj 	 simple cases can't be used.  */
2282*38fd1498Szrj       const int min_precision = targetm.min_arithmetic_precision ();
2283*38fd1498Szrj       if (orig_precres == precres && precres < min_precision)
2284*38fd1498Szrj 	;
2285*38fd1498Szrj       else if ((uns0_p && uns1_p && unsr_p && prec0 <= precres
2286*38fd1498Szrj 		&& prec1 <= precres)
2287*38fd1498Szrj 	  || ((!uns0_p || !uns1_p) && !unsr_p
2288*38fd1498Szrj 	      && prec0 + uns0_p <= precres
2289*38fd1498Szrj 	      && prec1 + uns1_p <= precres))
2290*38fd1498Szrj 	{
2291*38fd1498Szrj 	  arg0 = fold_convert_loc (loc, type, arg0);
2292*38fd1498Szrj 	  arg1 = fold_convert_loc (loc, type, arg1);
2293*38fd1498Szrj 	  switch (code)
2294*38fd1498Szrj 	    {
2295*38fd1498Szrj 	    case MINUS_EXPR:
2296*38fd1498Szrj 	      if (integer_zerop (arg0) && !unsr_p)
2297*38fd1498Szrj 		{
2298*38fd1498Szrj 		  expand_neg_overflow (loc, lhs, arg1, false, NULL);
2299*38fd1498Szrj 		  return;
2300*38fd1498Szrj 		}
2301*38fd1498Szrj 	      /* FALLTHRU */
2302*38fd1498Szrj 	    case PLUS_EXPR:
2303*38fd1498Szrj 	      expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
2304*38fd1498Szrj 				      unsr_p, unsr_p, false, NULL);
2305*38fd1498Szrj 	      return;
2306*38fd1498Szrj 	    case MULT_EXPR:
2307*38fd1498Szrj 	      expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
2308*38fd1498Szrj 				   unsr_p, unsr_p, false, NULL);
2309*38fd1498Szrj 	      return;
2310*38fd1498Szrj 	    default:
2311*38fd1498Szrj 	      gcc_unreachable ();
2312*38fd1498Szrj 	    }
2313*38fd1498Szrj 	}
2314*38fd1498Szrj 
2315*38fd1498Szrj       /* For sub-word operations, retry with a wider type first.  */
2316*38fd1498Szrj       if (orig_precres == precres && precop <= BITS_PER_WORD)
2317*38fd1498Szrj 	{
2318*38fd1498Szrj 	  int p = MAX (min_precision, precop);
2319*38fd1498Szrj 	  scalar_int_mode m = smallest_int_mode_for_size (p);
2320*38fd1498Szrj 	  tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
2321*38fd1498Szrj 							uns0_p && uns1_p
2322*38fd1498Szrj 							&& unsr_p);
2323*38fd1498Szrj 	  p = TYPE_PRECISION (optype);
2324*38fd1498Szrj 	  if (p > precres)
2325*38fd1498Szrj 	    {
2326*38fd1498Szrj 	      precres = p;
2327*38fd1498Szrj 	      unsr_p = TYPE_UNSIGNED (optype);
2328*38fd1498Szrj 	      type = optype;
2329*38fd1498Szrj 	      continue;
2330*38fd1498Szrj 	    }
2331*38fd1498Szrj 	}
2332*38fd1498Szrj 
2333*38fd1498Szrj       if (prec0 <= precres && prec1 <= precres)
2334*38fd1498Szrj 	{
2335*38fd1498Szrj 	  tree types[2];
2336*38fd1498Szrj 	  if (unsr_p)
2337*38fd1498Szrj 	    {
2338*38fd1498Szrj 	      types[0] = build_nonstandard_integer_type (precres, 0);
2339*38fd1498Szrj 	      types[1] = type;
2340*38fd1498Szrj 	    }
2341*38fd1498Szrj 	  else
2342*38fd1498Szrj 	    {
2343*38fd1498Szrj 	      types[0] = type;
2344*38fd1498Szrj 	      types[1] = build_nonstandard_integer_type (precres, 1);
2345*38fd1498Szrj 	    }
2346*38fd1498Szrj 	  arg0 = fold_convert_loc (loc, types[uns0_p], arg0);
2347*38fd1498Szrj 	  arg1 = fold_convert_loc (loc, types[uns1_p], arg1);
2348*38fd1498Szrj 	  if (code != MULT_EXPR)
2349*38fd1498Szrj 	    expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
2350*38fd1498Szrj 				    uns0_p, uns1_p, false, NULL);
2351*38fd1498Szrj 	  else
2352*38fd1498Szrj 	    expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
2353*38fd1498Szrj 				 uns0_p, uns1_p, false, NULL);
2354*38fd1498Szrj 	  return;
2355*38fd1498Szrj 	}
2356*38fd1498Szrj 
2357*38fd1498Szrj       /* Retry with a wider type.  */
2358*38fd1498Szrj       if (orig_precres == precres)
2359*38fd1498Szrj 	{
2360*38fd1498Szrj 	  int p = MAX (prec0, prec1);
2361*38fd1498Szrj 	  scalar_int_mode m = smallest_int_mode_for_size (p);
2362*38fd1498Szrj 	  tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
2363*38fd1498Szrj 							uns0_p && uns1_p
2364*38fd1498Szrj 							&& unsr_p);
2365*38fd1498Szrj 	  p = TYPE_PRECISION (optype);
2366*38fd1498Szrj 	  if (p > precres)
2367*38fd1498Szrj 	    {
2368*38fd1498Szrj 	      precres = p;
2369*38fd1498Szrj 	      unsr_p = TYPE_UNSIGNED (optype);
2370*38fd1498Szrj 	      type = optype;
2371*38fd1498Szrj 	      continue;
2372*38fd1498Szrj 	    }
2373*38fd1498Szrj 	}
2374*38fd1498Szrj 
2375*38fd1498Szrj       gcc_unreachable ();
2376*38fd1498Szrj     }
2377*38fd1498Szrj   while (1);
2378*38fd1498Szrj }
2379*38fd1498Szrj 
2380*38fd1498Szrj /* Expand ADD_OVERFLOW STMT.  */
2381*38fd1498Szrj 
2382*38fd1498Szrj static void
expand_ADD_OVERFLOW(internal_fn,gcall * stmt)2383*38fd1498Szrj expand_ADD_OVERFLOW (internal_fn, gcall *stmt)
2384*38fd1498Szrj {
2385*38fd1498Szrj   expand_arith_overflow (PLUS_EXPR, stmt);
2386*38fd1498Szrj }
2387*38fd1498Szrj 
2388*38fd1498Szrj /* Expand SUB_OVERFLOW STMT.  */
2389*38fd1498Szrj 
2390*38fd1498Szrj static void
expand_SUB_OVERFLOW(internal_fn,gcall * stmt)2391*38fd1498Szrj expand_SUB_OVERFLOW (internal_fn, gcall *stmt)
2392*38fd1498Szrj {
2393*38fd1498Szrj   expand_arith_overflow (MINUS_EXPR, stmt);
2394*38fd1498Szrj }
2395*38fd1498Szrj 
2396*38fd1498Szrj /* Expand MUL_OVERFLOW STMT.  */
2397*38fd1498Szrj 
2398*38fd1498Szrj static void
expand_MUL_OVERFLOW(internal_fn,gcall * stmt)2399*38fd1498Szrj expand_MUL_OVERFLOW (internal_fn, gcall *stmt)
2400*38fd1498Szrj {
2401*38fd1498Szrj   expand_arith_overflow (MULT_EXPR, stmt);
2402*38fd1498Szrj }
2403*38fd1498Szrj 
2404*38fd1498Szrj /* This should get folded in tree-vectorizer.c.  */
2405*38fd1498Szrj 
2406*38fd1498Szrj static void
expand_LOOP_VECTORIZED(internal_fn,gcall *)2407*38fd1498Szrj expand_LOOP_VECTORIZED (internal_fn, gcall *)
2408*38fd1498Szrj {
2409*38fd1498Szrj   gcc_unreachable ();
2410*38fd1498Szrj }
2411*38fd1498Szrj 
2412*38fd1498Szrj /* This should get folded in tree-vectorizer.c.  */
2413*38fd1498Szrj 
2414*38fd1498Szrj static void
expand_LOOP_DIST_ALIAS(internal_fn,gcall *)2415*38fd1498Szrj expand_LOOP_DIST_ALIAS (internal_fn, gcall *)
2416*38fd1498Szrj {
2417*38fd1498Szrj   gcc_unreachable ();
2418*38fd1498Szrj }
2419*38fd1498Szrj 
2420*38fd1498Szrj /* Return a memory reference of type TYPE for argument INDEX of STMT.
2421*38fd1498Szrj    Use argument INDEX + 1 to derive the second (TBAA) operand.  */
2422*38fd1498Szrj 
2423*38fd1498Szrj static tree
expand_call_mem_ref(tree type,gcall * stmt,int index)2424*38fd1498Szrj expand_call_mem_ref (tree type, gcall *stmt, int index)
2425*38fd1498Szrj {
2426*38fd1498Szrj   tree addr = gimple_call_arg (stmt, index);
2427*38fd1498Szrj   tree alias_ptr_type = TREE_TYPE (gimple_call_arg (stmt, index + 1));
2428*38fd1498Szrj   unsigned int align = tree_to_shwi (gimple_call_arg (stmt, index + 1));
2429*38fd1498Szrj   if (TYPE_ALIGN (type) != align)
2430*38fd1498Szrj     type = build_aligned_type (type, align);
2431*38fd1498Szrj 
2432*38fd1498Szrj   tree tmp = addr;
2433*38fd1498Szrj   if (TREE_CODE (tmp) == SSA_NAME)
2434*38fd1498Szrj     {
2435*38fd1498Szrj       gimple *def = SSA_NAME_DEF_STMT (tmp);
2436*38fd1498Szrj       if (gimple_assign_single_p (def))
2437*38fd1498Szrj 	tmp = gimple_assign_rhs1 (def);
2438*38fd1498Szrj     }
2439*38fd1498Szrj 
2440*38fd1498Szrj   if (TREE_CODE (tmp) == ADDR_EXPR)
2441*38fd1498Szrj     {
2442*38fd1498Szrj       tree mem = TREE_OPERAND (tmp, 0);
2443*38fd1498Szrj       if (TREE_CODE (mem) == TARGET_MEM_REF
2444*38fd1498Szrj 	  && types_compatible_p (TREE_TYPE (mem), type))
2445*38fd1498Szrj 	{
2446*38fd1498Szrj 	  tree offset = TMR_OFFSET (mem);
2447*38fd1498Szrj 	  if (type != TREE_TYPE (mem)
2448*38fd1498Szrj 	      || alias_ptr_type != TREE_TYPE (offset)
2449*38fd1498Szrj 	      || !integer_zerop (offset))
2450*38fd1498Szrj 	    {
2451*38fd1498Szrj 	      mem = copy_node (mem);
2452*38fd1498Szrj 	      TMR_OFFSET (mem) = wide_int_to_tree (alias_ptr_type,
2453*38fd1498Szrj 						   wi::to_poly_wide (offset));
2454*38fd1498Szrj 	      TREE_TYPE (mem) = type;
2455*38fd1498Szrj 	    }
2456*38fd1498Szrj 	  return mem;
2457*38fd1498Szrj 	}
2458*38fd1498Szrj     }
2459*38fd1498Szrj 
2460*38fd1498Szrj   return fold_build2 (MEM_REF, type, addr, build_int_cst (alias_ptr_type, 0));
2461*38fd1498Szrj }
2462*38fd1498Szrj 
2463*38fd1498Szrj /* Expand MASK_LOAD{,_LANES} call STMT using optab OPTAB.  */
2464*38fd1498Szrj 
2465*38fd1498Szrj static void
expand_mask_load_optab_fn(internal_fn,gcall * stmt,convert_optab optab)2466*38fd1498Szrj expand_mask_load_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
2467*38fd1498Szrj {
2468*38fd1498Szrj   struct expand_operand ops[3];
2469*38fd1498Szrj   tree type, lhs, rhs, maskt;
2470*38fd1498Szrj   rtx mem, target, mask;
2471*38fd1498Szrj   insn_code icode;
2472*38fd1498Szrj 
2473*38fd1498Szrj   maskt = gimple_call_arg (stmt, 2);
2474*38fd1498Szrj   lhs = gimple_call_lhs (stmt);
2475*38fd1498Szrj   if (lhs == NULL_TREE)
2476*38fd1498Szrj     return;
2477*38fd1498Szrj   type = TREE_TYPE (lhs);
2478*38fd1498Szrj   rhs = expand_call_mem_ref (type, stmt, 0);
2479*38fd1498Szrj 
2480*38fd1498Szrj   if (optab == vec_mask_load_lanes_optab)
2481*38fd1498Szrj     icode = get_multi_vector_move (type, optab);
2482*38fd1498Szrj   else
2483*38fd1498Szrj     icode = convert_optab_handler (optab, TYPE_MODE (type),
2484*38fd1498Szrj 				   TYPE_MODE (TREE_TYPE (maskt)));
2485*38fd1498Szrj 
2486*38fd1498Szrj   mem = expand_expr (rhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2487*38fd1498Szrj   gcc_assert (MEM_P (mem));
2488*38fd1498Szrj   mask = expand_normal (maskt);
2489*38fd1498Szrj   target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2490*38fd1498Szrj   create_output_operand (&ops[0], target, TYPE_MODE (type));
2491*38fd1498Szrj   create_fixed_operand (&ops[1], mem);
2492*38fd1498Szrj   create_input_operand (&ops[2], mask, TYPE_MODE (TREE_TYPE (maskt)));
2493*38fd1498Szrj   expand_insn (icode, 3, ops);
2494*38fd1498Szrj }
2495*38fd1498Szrj 
2496*38fd1498Szrj #define expand_mask_load_lanes_optab_fn expand_mask_load_optab_fn
2497*38fd1498Szrj 
2498*38fd1498Szrj /* Expand MASK_STORE{,_LANES} call STMT using optab OPTAB.  */
2499*38fd1498Szrj 
2500*38fd1498Szrj static void
expand_mask_store_optab_fn(internal_fn,gcall * stmt,convert_optab optab)2501*38fd1498Szrj expand_mask_store_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
2502*38fd1498Szrj {
2503*38fd1498Szrj   struct expand_operand ops[3];
2504*38fd1498Szrj   tree type, lhs, rhs, maskt;
2505*38fd1498Szrj   rtx mem, reg, mask;
2506*38fd1498Szrj   insn_code icode;
2507*38fd1498Szrj 
2508*38fd1498Szrj   maskt = gimple_call_arg (stmt, 2);
2509*38fd1498Szrj   rhs = gimple_call_arg (stmt, 3);
2510*38fd1498Szrj   type = TREE_TYPE (rhs);
2511*38fd1498Szrj   lhs = expand_call_mem_ref (type, stmt, 0);
2512*38fd1498Szrj 
2513*38fd1498Szrj   if (optab == vec_mask_store_lanes_optab)
2514*38fd1498Szrj     icode = get_multi_vector_move (type, optab);
2515*38fd1498Szrj   else
2516*38fd1498Szrj     icode = convert_optab_handler (optab, TYPE_MODE (type),
2517*38fd1498Szrj 				   TYPE_MODE (TREE_TYPE (maskt)));
2518*38fd1498Szrj 
2519*38fd1498Szrj   mem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2520*38fd1498Szrj   gcc_assert (MEM_P (mem));
2521*38fd1498Szrj   mask = expand_normal (maskt);
2522*38fd1498Szrj   reg = expand_normal (rhs);
2523*38fd1498Szrj   create_fixed_operand (&ops[0], mem);
2524*38fd1498Szrj   create_input_operand (&ops[1], reg, TYPE_MODE (type));
2525*38fd1498Szrj   create_input_operand (&ops[2], mask, TYPE_MODE (TREE_TYPE (maskt)));
2526*38fd1498Szrj   expand_insn (icode, 3, ops);
2527*38fd1498Szrj }
2528*38fd1498Szrj 
2529*38fd1498Szrj #define expand_mask_store_lanes_optab_fn expand_mask_store_optab_fn
2530*38fd1498Szrj 
2531*38fd1498Szrj static void
expand_ABNORMAL_DISPATCHER(internal_fn,gcall *)2532*38fd1498Szrj expand_ABNORMAL_DISPATCHER (internal_fn, gcall *)
2533*38fd1498Szrj {
2534*38fd1498Szrj }
2535*38fd1498Szrj 
2536*38fd1498Szrj static void
expand_BUILTIN_EXPECT(internal_fn,gcall * stmt)2537*38fd1498Szrj expand_BUILTIN_EXPECT (internal_fn, gcall *stmt)
2538*38fd1498Szrj {
2539*38fd1498Szrj   /* When guessing was done, the hints should be already stripped away.  */
2540*38fd1498Szrj   gcc_assert (!flag_guess_branch_prob || optimize == 0 || seen_error ());
2541*38fd1498Szrj 
2542*38fd1498Szrj   rtx target;
2543*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
2544*38fd1498Szrj   if (lhs)
2545*38fd1498Szrj     target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2546*38fd1498Szrj   else
2547*38fd1498Szrj     target = const0_rtx;
2548*38fd1498Szrj   rtx val = expand_expr (gimple_call_arg (stmt, 0), target, VOIDmode, EXPAND_NORMAL);
2549*38fd1498Szrj   if (lhs && val != target)
2550*38fd1498Szrj     emit_move_insn (target, val);
2551*38fd1498Szrj }
2552*38fd1498Szrj 
2553*38fd1498Szrj /* IFN_VA_ARG is supposed to be expanded at pass_stdarg.  So this dummy function
2554*38fd1498Szrj    should never be called.  */
2555*38fd1498Szrj 
2556*38fd1498Szrj static void
expand_VA_ARG(internal_fn,gcall *)2557*38fd1498Szrj expand_VA_ARG (internal_fn, gcall *)
2558*38fd1498Szrj {
2559*38fd1498Szrj   gcc_unreachable ();
2560*38fd1498Szrj }
2561*38fd1498Szrj 
2562*38fd1498Szrj /* Expand the IFN_UNIQUE function according to its first argument.  */
2563*38fd1498Szrj 
2564*38fd1498Szrj static void
expand_UNIQUE(internal_fn,gcall * stmt)2565*38fd1498Szrj expand_UNIQUE (internal_fn, gcall *stmt)
2566*38fd1498Szrj {
2567*38fd1498Szrj   rtx pattern = NULL_RTX;
2568*38fd1498Szrj   enum ifn_unique_kind kind
2569*38fd1498Szrj     = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (stmt, 0));
2570*38fd1498Szrj 
2571*38fd1498Szrj   switch (kind)
2572*38fd1498Szrj     {
2573*38fd1498Szrj     default:
2574*38fd1498Szrj       gcc_unreachable ();
2575*38fd1498Szrj 
2576*38fd1498Szrj     case IFN_UNIQUE_UNSPEC:
2577*38fd1498Szrj       if (targetm.have_unique ())
2578*38fd1498Szrj 	pattern = targetm.gen_unique ();
2579*38fd1498Szrj       break;
2580*38fd1498Szrj 
2581*38fd1498Szrj     case IFN_UNIQUE_OACC_FORK:
2582*38fd1498Szrj     case IFN_UNIQUE_OACC_JOIN:
2583*38fd1498Szrj       if (targetm.have_oacc_fork () && targetm.have_oacc_join ())
2584*38fd1498Szrj 	{
2585*38fd1498Szrj 	  tree lhs = gimple_call_lhs (stmt);
2586*38fd1498Szrj 	  rtx target = const0_rtx;
2587*38fd1498Szrj 
2588*38fd1498Szrj 	  if (lhs)
2589*38fd1498Szrj 	    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2590*38fd1498Szrj 
2591*38fd1498Szrj 	  rtx data_dep = expand_normal (gimple_call_arg (stmt, 1));
2592*38fd1498Szrj 	  rtx axis = expand_normal (gimple_call_arg (stmt, 2));
2593*38fd1498Szrj 
2594*38fd1498Szrj 	  if (kind == IFN_UNIQUE_OACC_FORK)
2595*38fd1498Szrj 	    pattern = targetm.gen_oacc_fork (target, data_dep, axis);
2596*38fd1498Szrj 	  else
2597*38fd1498Szrj 	    pattern = targetm.gen_oacc_join (target, data_dep, axis);
2598*38fd1498Szrj 	}
2599*38fd1498Szrj       else
2600*38fd1498Szrj 	gcc_unreachable ();
2601*38fd1498Szrj       break;
2602*38fd1498Szrj     }
2603*38fd1498Szrj 
2604*38fd1498Szrj   if (pattern)
2605*38fd1498Szrj     emit_insn (pattern);
2606*38fd1498Szrj }
2607*38fd1498Szrj 
2608*38fd1498Szrj /* The size of an OpenACC compute dimension.  */
2609*38fd1498Szrj 
2610*38fd1498Szrj static void
expand_GOACC_DIM_SIZE(internal_fn,gcall * stmt)2611*38fd1498Szrj expand_GOACC_DIM_SIZE (internal_fn, gcall *stmt)
2612*38fd1498Szrj {
2613*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
2614*38fd1498Szrj 
2615*38fd1498Szrj   if (!lhs)
2616*38fd1498Szrj     return;
2617*38fd1498Szrj 
2618*38fd1498Szrj   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2619*38fd1498Szrj   if (targetm.have_oacc_dim_size ())
2620*38fd1498Szrj     {
2621*38fd1498Szrj       rtx dim = expand_expr (gimple_call_arg (stmt, 0), NULL_RTX,
2622*38fd1498Szrj 			     VOIDmode, EXPAND_NORMAL);
2623*38fd1498Szrj       emit_insn (targetm.gen_oacc_dim_size (target, dim));
2624*38fd1498Szrj     }
2625*38fd1498Szrj   else
2626*38fd1498Szrj     emit_move_insn (target, GEN_INT (1));
2627*38fd1498Szrj }
2628*38fd1498Szrj 
2629*38fd1498Szrj /* The position of an OpenACC execution engine along one compute axis.  */
2630*38fd1498Szrj 
2631*38fd1498Szrj static void
expand_GOACC_DIM_POS(internal_fn,gcall * stmt)2632*38fd1498Szrj expand_GOACC_DIM_POS (internal_fn, gcall *stmt)
2633*38fd1498Szrj {
2634*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
2635*38fd1498Szrj 
2636*38fd1498Szrj   if (!lhs)
2637*38fd1498Szrj     return;
2638*38fd1498Szrj 
2639*38fd1498Szrj   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2640*38fd1498Szrj   if (targetm.have_oacc_dim_pos ())
2641*38fd1498Szrj     {
2642*38fd1498Szrj       rtx dim = expand_expr (gimple_call_arg (stmt, 0), NULL_RTX,
2643*38fd1498Szrj 			     VOIDmode, EXPAND_NORMAL);
2644*38fd1498Szrj       emit_insn (targetm.gen_oacc_dim_pos (target, dim));
2645*38fd1498Szrj     }
2646*38fd1498Szrj   else
2647*38fd1498Szrj     emit_move_insn (target, const0_rtx);
2648*38fd1498Szrj }
2649*38fd1498Szrj 
2650*38fd1498Szrj /* This is expanded by oacc_device_lower pass.  */
2651*38fd1498Szrj 
2652*38fd1498Szrj static void
expand_GOACC_LOOP(internal_fn,gcall *)2653*38fd1498Szrj expand_GOACC_LOOP (internal_fn, gcall *)
2654*38fd1498Szrj {
2655*38fd1498Szrj   gcc_unreachable ();
2656*38fd1498Szrj }
2657*38fd1498Szrj 
2658*38fd1498Szrj /* This is expanded by oacc_device_lower pass.  */
2659*38fd1498Szrj 
2660*38fd1498Szrj static void
expand_GOACC_REDUCTION(internal_fn,gcall *)2661*38fd1498Szrj expand_GOACC_REDUCTION (internal_fn, gcall *)
2662*38fd1498Szrj {
2663*38fd1498Szrj   gcc_unreachable ();
2664*38fd1498Szrj }
2665*38fd1498Szrj 
2666*38fd1498Szrj /* This is expanded by oacc_device_lower pass.  */
2667*38fd1498Szrj 
2668*38fd1498Szrj static void
expand_GOACC_TILE(internal_fn,gcall *)2669*38fd1498Szrj expand_GOACC_TILE (internal_fn, gcall *)
2670*38fd1498Szrj {
2671*38fd1498Szrj   gcc_unreachable ();
2672*38fd1498Szrj }
2673*38fd1498Szrj 
2674*38fd1498Szrj /* Set errno to EDOM.  */
2675*38fd1498Szrj 
2676*38fd1498Szrj static void
expand_SET_EDOM(internal_fn,gcall *)2677*38fd1498Szrj expand_SET_EDOM (internal_fn, gcall *)
2678*38fd1498Szrj {
2679*38fd1498Szrj #ifdef TARGET_EDOM
2680*38fd1498Szrj #ifdef GEN_ERRNO_RTX
2681*38fd1498Szrj   rtx errno_rtx = GEN_ERRNO_RTX;
2682*38fd1498Szrj #else
2683*38fd1498Szrj   rtx errno_rtx = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
2684*38fd1498Szrj #endif
2685*38fd1498Szrj   emit_move_insn (errno_rtx,
2686*38fd1498Szrj 		  gen_int_mode (TARGET_EDOM, GET_MODE (errno_rtx)));
2687*38fd1498Szrj #else
2688*38fd1498Szrj   gcc_unreachable ();
2689*38fd1498Szrj #endif
2690*38fd1498Szrj }
2691*38fd1498Szrj 
2692*38fd1498Szrj /* Expand atomic bit test and set.  */
2693*38fd1498Szrj 
2694*38fd1498Szrj static void
expand_ATOMIC_BIT_TEST_AND_SET(internal_fn,gcall * call)2695*38fd1498Szrj expand_ATOMIC_BIT_TEST_AND_SET (internal_fn, gcall *call)
2696*38fd1498Szrj {
2697*38fd1498Szrj   expand_ifn_atomic_bit_test_and (call);
2698*38fd1498Szrj }
2699*38fd1498Szrj 
2700*38fd1498Szrj /* Expand atomic bit test and complement.  */
2701*38fd1498Szrj 
2702*38fd1498Szrj static void
expand_ATOMIC_BIT_TEST_AND_COMPLEMENT(internal_fn,gcall * call)2703*38fd1498Szrj expand_ATOMIC_BIT_TEST_AND_COMPLEMENT (internal_fn, gcall *call)
2704*38fd1498Szrj {
2705*38fd1498Szrj   expand_ifn_atomic_bit_test_and (call);
2706*38fd1498Szrj }
2707*38fd1498Szrj 
2708*38fd1498Szrj /* Expand atomic bit test and reset.  */
2709*38fd1498Szrj 
2710*38fd1498Szrj static void
expand_ATOMIC_BIT_TEST_AND_RESET(internal_fn,gcall * call)2711*38fd1498Szrj expand_ATOMIC_BIT_TEST_AND_RESET (internal_fn, gcall *call)
2712*38fd1498Szrj {
2713*38fd1498Szrj   expand_ifn_atomic_bit_test_and (call);
2714*38fd1498Szrj }
2715*38fd1498Szrj 
2716*38fd1498Szrj /* Expand atomic bit test and set.  */
2717*38fd1498Szrj 
2718*38fd1498Szrj static void
expand_ATOMIC_COMPARE_EXCHANGE(internal_fn,gcall * call)2719*38fd1498Szrj expand_ATOMIC_COMPARE_EXCHANGE (internal_fn, gcall *call)
2720*38fd1498Szrj {
2721*38fd1498Szrj   expand_ifn_atomic_compare_exchange (call);
2722*38fd1498Szrj }
2723*38fd1498Szrj 
2724*38fd1498Szrj /* Expand LAUNDER to assignment, lhs = arg0.  */
2725*38fd1498Szrj 
2726*38fd1498Szrj static void
expand_LAUNDER(internal_fn,gcall * call)2727*38fd1498Szrj expand_LAUNDER (internal_fn, gcall *call)
2728*38fd1498Szrj {
2729*38fd1498Szrj   tree lhs = gimple_call_lhs (call);
2730*38fd1498Szrj 
2731*38fd1498Szrj   if (!lhs)
2732*38fd1498Szrj     return;
2733*38fd1498Szrj 
2734*38fd1498Szrj   expand_assignment (lhs, gimple_call_arg (call, 0), false);
2735*38fd1498Szrj }
2736*38fd1498Szrj 
2737*38fd1498Szrj /* Expand {MASK_,}SCATTER_STORE{S,U} call CALL using optab OPTAB.  */
2738*38fd1498Szrj 
2739*38fd1498Szrj static void
expand_scatter_store_optab_fn(internal_fn,gcall * stmt,direct_optab optab)2740*38fd1498Szrj expand_scatter_store_optab_fn (internal_fn, gcall *stmt, direct_optab optab)
2741*38fd1498Szrj {
2742*38fd1498Szrj   internal_fn ifn = gimple_call_internal_fn (stmt);
2743*38fd1498Szrj   int rhs_index = internal_fn_stored_value_index (ifn);
2744*38fd1498Szrj   int mask_index = internal_fn_mask_index (ifn);
2745*38fd1498Szrj   tree base = gimple_call_arg (stmt, 0);
2746*38fd1498Szrj   tree offset = gimple_call_arg (stmt, 1);
2747*38fd1498Szrj   tree scale = gimple_call_arg (stmt, 2);
2748*38fd1498Szrj   tree rhs = gimple_call_arg (stmt, rhs_index);
2749*38fd1498Szrj 
2750*38fd1498Szrj   rtx base_rtx = expand_normal (base);
2751*38fd1498Szrj   rtx offset_rtx = expand_normal (offset);
2752*38fd1498Szrj   HOST_WIDE_INT scale_int = tree_to_shwi (scale);
2753*38fd1498Szrj   rtx rhs_rtx = expand_normal (rhs);
2754*38fd1498Szrj 
2755*38fd1498Szrj   struct expand_operand ops[6];
2756*38fd1498Szrj   int i = 0;
2757*38fd1498Szrj   create_address_operand (&ops[i++], base_rtx);
2758*38fd1498Szrj   create_input_operand (&ops[i++], offset_rtx, TYPE_MODE (TREE_TYPE (offset)));
2759*38fd1498Szrj   create_integer_operand (&ops[i++], TYPE_UNSIGNED (TREE_TYPE (offset)));
2760*38fd1498Szrj   create_integer_operand (&ops[i++], scale_int);
2761*38fd1498Szrj   create_input_operand (&ops[i++], rhs_rtx, TYPE_MODE (TREE_TYPE (rhs)));
2762*38fd1498Szrj   if (mask_index >= 0)
2763*38fd1498Szrj     {
2764*38fd1498Szrj       tree mask = gimple_call_arg (stmt, mask_index);
2765*38fd1498Szrj       rtx mask_rtx = expand_normal (mask);
2766*38fd1498Szrj       create_input_operand (&ops[i++], mask_rtx, TYPE_MODE (TREE_TYPE (mask)));
2767*38fd1498Szrj     }
2768*38fd1498Szrj 
2769*38fd1498Szrj   insn_code icode = direct_optab_handler (optab, TYPE_MODE (TREE_TYPE (rhs)));
2770*38fd1498Szrj   expand_insn (icode, i, ops);
2771*38fd1498Szrj }
2772*38fd1498Szrj 
2773*38fd1498Szrj /* Expand {MASK_,}GATHER_LOAD call CALL using optab OPTAB.  */
2774*38fd1498Szrj 
2775*38fd1498Szrj static void
expand_gather_load_optab_fn(internal_fn,gcall * stmt,direct_optab optab)2776*38fd1498Szrj expand_gather_load_optab_fn (internal_fn, gcall *stmt, direct_optab optab)
2777*38fd1498Szrj {
2778*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
2779*38fd1498Szrj   tree base = gimple_call_arg (stmt, 0);
2780*38fd1498Szrj   tree offset = gimple_call_arg (stmt, 1);
2781*38fd1498Szrj   tree scale = gimple_call_arg (stmt, 2);
2782*38fd1498Szrj 
2783*38fd1498Szrj   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2784*38fd1498Szrj   rtx base_rtx = expand_normal (base);
2785*38fd1498Szrj   rtx offset_rtx = expand_normal (offset);
2786*38fd1498Szrj   HOST_WIDE_INT scale_int = tree_to_shwi (scale);
2787*38fd1498Szrj 
2788*38fd1498Szrj   int i = 0;
2789*38fd1498Szrj   struct expand_operand ops[6];
2790*38fd1498Szrj   create_output_operand (&ops[i++], lhs_rtx, TYPE_MODE (TREE_TYPE (lhs)));
2791*38fd1498Szrj   create_address_operand (&ops[i++], base_rtx);
2792*38fd1498Szrj   create_input_operand (&ops[i++], offset_rtx, TYPE_MODE (TREE_TYPE (offset)));
2793*38fd1498Szrj   create_integer_operand (&ops[i++], TYPE_UNSIGNED (TREE_TYPE (offset)));
2794*38fd1498Szrj   create_integer_operand (&ops[i++], scale_int);
2795*38fd1498Szrj   if (optab == mask_gather_load_optab)
2796*38fd1498Szrj     {
2797*38fd1498Szrj       tree mask = gimple_call_arg (stmt, 3);
2798*38fd1498Szrj       rtx mask_rtx = expand_normal (mask);
2799*38fd1498Szrj       create_input_operand (&ops[i++], mask_rtx, TYPE_MODE (TREE_TYPE (mask)));
2800*38fd1498Szrj     }
2801*38fd1498Szrj   insn_code icode = direct_optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)));
2802*38fd1498Szrj   expand_insn (icode, i, ops);
2803*38fd1498Szrj }
2804*38fd1498Szrj 
2805*38fd1498Szrj /* Expand DIVMOD() using:
2806*38fd1498Szrj  a) optab handler for udivmod/sdivmod if it is available.
2807*38fd1498Szrj  b) If optab_handler doesn't exist, generate call to
2808*38fd1498Szrj     target-specific divmod libfunc.  */
2809*38fd1498Szrj 
2810*38fd1498Szrj static void
expand_DIVMOD(internal_fn,gcall * call_stmt)2811*38fd1498Szrj expand_DIVMOD (internal_fn, gcall *call_stmt)
2812*38fd1498Szrj {
2813*38fd1498Szrj   tree lhs = gimple_call_lhs (call_stmt);
2814*38fd1498Szrj   tree arg0 = gimple_call_arg (call_stmt, 0);
2815*38fd1498Szrj   tree arg1 = gimple_call_arg (call_stmt, 1);
2816*38fd1498Szrj 
2817*38fd1498Szrj   gcc_assert (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE);
2818*38fd1498Szrj   tree type = TREE_TYPE (TREE_TYPE (lhs));
2819*38fd1498Szrj   machine_mode mode = TYPE_MODE (type);
2820*38fd1498Szrj   bool unsignedp = TYPE_UNSIGNED (type);
2821*38fd1498Szrj   optab tab = (unsignedp) ? udivmod_optab : sdivmod_optab;
2822*38fd1498Szrj 
2823*38fd1498Szrj   rtx op0 = expand_normal (arg0);
2824*38fd1498Szrj   rtx op1 = expand_normal (arg1);
2825*38fd1498Szrj   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2826*38fd1498Szrj 
2827*38fd1498Szrj   rtx quotient, remainder, libfunc;
2828*38fd1498Szrj 
2829*38fd1498Szrj   /* Check if optab_handler exists for divmod_optab for given mode.  */
2830*38fd1498Szrj   if (optab_handler (tab, mode) != CODE_FOR_nothing)
2831*38fd1498Szrj     {
2832*38fd1498Szrj       quotient = gen_reg_rtx (mode);
2833*38fd1498Szrj       remainder = gen_reg_rtx (mode);
2834*38fd1498Szrj       expand_twoval_binop (tab, op0, op1, quotient, remainder, unsignedp);
2835*38fd1498Szrj     }
2836*38fd1498Szrj 
2837*38fd1498Szrj   /* Generate call to divmod libfunc if it exists.  */
2838*38fd1498Szrj   else if ((libfunc = optab_libfunc (tab, mode)) != NULL_RTX)
2839*38fd1498Szrj     targetm.expand_divmod_libfunc (libfunc, mode, op0, op1,
2840*38fd1498Szrj 				   &quotient, &remainder);
2841*38fd1498Szrj 
2842*38fd1498Szrj   else
2843*38fd1498Szrj     gcc_unreachable ();
2844*38fd1498Szrj 
2845*38fd1498Szrj   /* Wrap the return value (quotient, remainder) within COMPLEX_EXPR.  */
2846*38fd1498Szrj   expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
2847*38fd1498Szrj 		       make_tree (TREE_TYPE (arg0), quotient),
2848*38fd1498Szrj 		       make_tree (TREE_TYPE (arg1), remainder)),
2849*38fd1498Szrj 	       target, VOIDmode, EXPAND_NORMAL);
2850*38fd1498Szrj }
2851*38fd1498Szrj 
2852*38fd1498Szrj /* Expand a NOP.  */
2853*38fd1498Szrj 
2854*38fd1498Szrj static void
expand_NOP(internal_fn,gcall *)2855*38fd1498Szrj expand_NOP (internal_fn, gcall *)
2856*38fd1498Szrj {
2857*38fd1498Szrj   /* Nothing.  But it shouldn't really prevail.  */
2858*38fd1498Szrj }
2859*38fd1498Szrj 
2860*38fd1498Szrj /* Expand a call to FN using the operands in STMT.  FN has a single
2861*38fd1498Szrj    output operand and NARGS input operands.  */
2862*38fd1498Szrj 
2863*38fd1498Szrj static void
expand_direct_optab_fn(internal_fn fn,gcall * stmt,direct_optab optab,unsigned int nargs)2864*38fd1498Szrj expand_direct_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab,
2865*38fd1498Szrj 			unsigned int nargs)
2866*38fd1498Szrj {
2867*38fd1498Szrj   expand_operand *ops = XALLOCAVEC (expand_operand, nargs + 1);
2868*38fd1498Szrj 
2869*38fd1498Szrj   tree_pair types = direct_internal_fn_types (fn, stmt);
2870*38fd1498Szrj   insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first));
2871*38fd1498Szrj 
2872*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
2873*38fd1498Szrj   tree lhs_type = TREE_TYPE (lhs);
2874*38fd1498Szrj   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2875*38fd1498Szrj 
2876*38fd1498Szrj   /* Do not assign directly to a promoted subreg, since there is no
2877*38fd1498Szrj      guarantee that the instruction will leave the upper bits of the
2878*38fd1498Szrj      register in the state required by SUBREG_PROMOTED_SIGN.  */
2879*38fd1498Szrj   rtx dest = lhs_rtx;
2880*38fd1498Szrj   if (GET_CODE (dest) == SUBREG && SUBREG_PROMOTED_VAR_P (dest))
2881*38fd1498Szrj     dest = NULL_RTX;
2882*38fd1498Szrj 
2883*38fd1498Szrj   create_output_operand (&ops[0], dest, insn_data[icode].operand[0].mode);
2884*38fd1498Szrj 
2885*38fd1498Szrj   for (unsigned int i = 0; i < nargs; ++i)
2886*38fd1498Szrj     {
2887*38fd1498Szrj       tree rhs = gimple_call_arg (stmt, i);
2888*38fd1498Szrj       tree rhs_type = TREE_TYPE (rhs);
2889*38fd1498Szrj       rtx rhs_rtx = expand_normal (rhs);
2890*38fd1498Szrj       if (INTEGRAL_TYPE_P (rhs_type))
2891*38fd1498Szrj 	create_convert_operand_from (&ops[i + 1], rhs_rtx,
2892*38fd1498Szrj 				     TYPE_MODE (rhs_type),
2893*38fd1498Szrj 				     TYPE_UNSIGNED (rhs_type));
2894*38fd1498Szrj       else
2895*38fd1498Szrj 	create_input_operand (&ops[i + 1], rhs_rtx, TYPE_MODE (rhs_type));
2896*38fd1498Szrj     }
2897*38fd1498Szrj 
2898*38fd1498Szrj   expand_insn (icode, nargs + 1, ops);
2899*38fd1498Szrj   if (!rtx_equal_p (lhs_rtx, ops[0].value))
2900*38fd1498Szrj     {
2901*38fd1498Szrj       /* If the return value has an integral type, convert the instruction
2902*38fd1498Szrj 	 result to that type.  This is useful for things that return an
2903*38fd1498Szrj 	 int regardless of the size of the input.  If the instruction result
2904*38fd1498Szrj 	 is smaller than required, assume that it is signed.
2905*38fd1498Szrj 
2906*38fd1498Szrj 	 If the return value has a nonintegral type, its mode must match
2907*38fd1498Szrj 	 the instruction result.  */
2908*38fd1498Szrj       if (GET_CODE (lhs_rtx) == SUBREG && SUBREG_PROMOTED_VAR_P (lhs_rtx))
2909*38fd1498Szrj 	{
2910*38fd1498Szrj 	  /* If this is a scalar in a register that is stored in a wider
2911*38fd1498Szrj 	     mode than the declared mode, compute the result into its
2912*38fd1498Szrj 	     declared mode and then convert to the wider mode.  */
2913*38fd1498Szrj 	  gcc_checking_assert (INTEGRAL_TYPE_P (lhs_type));
2914*38fd1498Szrj 	  rtx tmp = convert_to_mode (GET_MODE (lhs_rtx), ops[0].value, 0);
2915*38fd1498Szrj 	  convert_move (SUBREG_REG (lhs_rtx), tmp,
2916*38fd1498Szrj 			SUBREG_PROMOTED_SIGN (lhs_rtx));
2917*38fd1498Szrj 	}
2918*38fd1498Szrj       else if (GET_MODE (lhs_rtx) == GET_MODE (ops[0].value))
2919*38fd1498Szrj 	emit_move_insn (lhs_rtx, ops[0].value);
2920*38fd1498Szrj       else
2921*38fd1498Szrj 	{
2922*38fd1498Szrj 	  gcc_checking_assert (INTEGRAL_TYPE_P (lhs_type));
2923*38fd1498Szrj 	  convert_move (lhs_rtx, ops[0].value, 0);
2924*38fd1498Szrj 	}
2925*38fd1498Szrj     }
2926*38fd1498Szrj }
2927*38fd1498Szrj 
2928*38fd1498Szrj /* Expand WHILE_ULT call STMT using optab OPTAB.  */
2929*38fd1498Szrj 
2930*38fd1498Szrj static void
expand_while_optab_fn(internal_fn,gcall * stmt,convert_optab optab)2931*38fd1498Szrj expand_while_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
2932*38fd1498Szrj {
2933*38fd1498Szrj   expand_operand ops[3];
2934*38fd1498Szrj   tree rhs_type[2];
2935*38fd1498Szrj 
2936*38fd1498Szrj   tree lhs = gimple_call_lhs (stmt);
2937*38fd1498Szrj   tree lhs_type = TREE_TYPE (lhs);
2938*38fd1498Szrj   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2939*38fd1498Szrj   create_output_operand (&ops[0], lhs_rtx, TYPE_MODE (lhs_type));
2940*38fd1498Szrj 
2941*38fd1498Szrj   for (unsigned int i = 0; i < 2; ++i)
2942*38fd1498Szrj     {
2943*38fd1498Szrj       tree rhs = gimple_call_arg (stmt, i);
2944*38fd1498Szrj       rhs_type[i] = TREE_TYPE (rhs);
2945*38fd1498Szrj       rtx rhs_rtx = expand_normal (rhs);
2946*38fd1498Szrj       create_input_operand (&ops[i + 1], rhs_rtx, TYPE_MODE (rhs_type[i]));
2947*38fd1498Szrj     }
2948*38fd1498Szrj 
2949*38fd1498Szrj   insn_code icode = convert_optab_handler (optab, TYPE_MODE (rhs_type[0]),
2950*38fd1498Szrj 					   TYPE_MODE (lhs_type));
2951*38fd1498Szrj 
2952*38fd1498Szrj   expand_insn (icode, 3, ops);
2953*38fd1498Szrj   if (!rtx_equal_p (lhs_rtx, ops[0].value))
2954*38fd1498Szrj     emit_move_insn (lhs_rtx, ops[0].value);
2955*38fd1498Szrj }
2956*38fd1498Szrj 
2957*38fd1498Szrj /* Expanders for optabs that can use expand_direct_optab_fn.  */
2958*38fd1498Szrj 
2959*38fd1498Szrj #define expand_unary_optab_fn(FN, STMT, OPTAB) \
2960*38fd1498Szrj   expand_direct_optab_fn (FN, STMT, OPTAB, 1)
2961*38fd1498Szrj 
2962*38fd1498Szrj #define expand_binary_optab_fn(FN, STMT, OPTAB) \
2963*38fd1498Szrj   expand_direct_optab_fn (FN, STMT, OPTAB, 2)
2964*38fd1498Szrj 
2965*38fd1498Szrj #define expand_cond_unary_optab_fn(FN, STMT, OPTAB) \
2966*38fd1498Szrj   expand_direct_optab_fn (FN, STMT, OPTAB, 2)
2967*38fd1498Szrj 
2968*38fd1498Szrj #define expand_cond_binary_optab_fn(FN, STMT, OPTAB) \
2969*38fd1498Szrj   expand_direct_optab_fn (FN, STMT, OPTAB, 3)
2970*38fd1498Szrj 
2971*38fd1498Szrj #define expand_fold_extract_optab_fn(FN, STMT, OPTAB) \
2972*38fd1498Szrj   expand_direct_optab_fn (FN, STMT, OPTAB, 3)
2973*38fd1498Szrj 
2974*38fd1498Szrj #define expand_fold_left_optab_fn(FN, STMT, OPTAB) \
2975*38fd1498Szrj   expand_direct_optab_fn (FN, STMT, OPTAB, 2)
2976*38fd1498Szrj 
2977*38fd1498Szrj /* RETURN_TYPE and ARGS are a return type and argument list that are
2978*38fd1498Szrj    in principle compatible with FN (which satisfies direct_internal_fn_p).
2979*38fd1498Szrj    Return the types that should be used to determine whether the
2980*38fd1498Szrj    target supports FN.  */
2981*38fd1498Szrj 
2982*38fd1498Szrj tree_pair
direct_internal_fn_types(internal_fn fn,tree return_type,tree * args)2983*38fd1498Szrj direct_internal_fn_types (internal_fn fn, tree return_type, tree *args)
2984*38fd1498Szrj {
2985*38fd1498Szrj   const direct_internal_fn_info &info = direct_internal_fn (fn);
2986*38fd1498Szrj   tree type0 = (info.type0 < 0 ? return_type : TREE_TYPE (args[info.type0]));
2987*38fd1498Szrj   tree type1 = (info.type1 < 0 ? return_type : TREE_TYPE (args[info.type1]));
2988*38fd1498Szrj   return tree_pair (type0, type1);
2989*38fd1498Szrj }
2990*38fd1498Szrj 
2991*38fd1498Szrj /* CALL is a call whose return type and arguments are in principle
2992*38fd1498Szrj    compatible with FN (which satisfies direct_internal_fn_p).  Return the
2993*38fd1498Szrj    types that should be used to determine whether the target supports FN.  */
2994*38fd1498Szrj 
2995*38fd1498Szrj tree_pair
direct_internal_fn_types(internal_fn fn,gcall * call)2996*38fd1498Szrj direct_internal_fn_types (internal_fn fn, gcall *call)
2997*38fd1498Szrj {
2998*38fd1498Szrj   const direct_internal_fn_info &info = direct_internal_fn (fn);
2999*38fd1498Szrj   tree op0 = (info.type0 < 0
3000*38fd1498Szrj 	      ? gimple_call_lhs (call)
3001*38fd1498Szrj 	      : gimple_call_arg (call, info.type0));
3002*38fd1498Szrj   tree op1 = (info.type1 < 0
3003*38fd1498Szrj 	      ? gimple_call_lhs (call)
3004*38fd1498Szrj 	      : gimple_call_arg (call, info.type1));
3005*38fd1498Szrj   return tree_pair (TREE_TYPE (op0), TREE_TYPE (op1));
3006*38fd1498Szrj }
3007*38fd1498Szrj 
3008*38fd1498Szrj /* Return true if OPTAB is supported for TYPES (whose modes should be
3009*38fd1498Szrj    the same) when the optimization type is OPT_TYPE.  Used for simple
3010*38fd1498Szrj    direct optabs.  */
3011*38fd1498Szrj 
3012*38fd1498Szrj static bool
direct_optab_supported_p(direct_optab optab,tree_pair types,optimization_type opt_type)3013*38fd1498Szrj direct_optab_supported_p (direct_optab optab, tree_pair types,
3014*38fd1498Szrj 			  optimization_type opt_type)
3015*38fd1498Szrj {
3016*38fd1498Szrj   machine_mode mode = TYPE_MODE (types.first);
3017*38fd1498Szrj   gcc_checking_assert (mode == TYPE_MODE (types.second));
3018*38fd1498Szrj   return direct_optab_handler (optab, mode, opt_type) != CODE_FOR_nothing;
3019*38fd1498Szrj }
3020*38fd1498Szrj 
3021*38fd1498Szrj /* Return true if OPTAB is supported for TYPES, where the first type
3022*38fd1498Szrj    is the destination and the second type is the source.  Used for
3023*38fd1498Szrj    convert optabs.  */
3024*38fd1498Szrj 
3025*38fd1498Szrj static bool
convert_optab_supported_p(convert_optab optab,tree_pair types,optimization_type opt_type)3026*38fd1498Szrj convert_optab_supported_p (convert_optab optab, tree_pair types,
3027*38fd1498Szrj 			   optimization_type opt_type)
3028*38fd1498Szrj {
3029*38fd1498Szrj   return (convert_optab_handler (optab, TYPE_MODE (types.first),
3030*38fd1498Szrj 				 TYPE_MODE (types.second), opt_type)
3031*38fd1498Szrj 	  != CODE_FOR_nothing);
3032*38fd1498Szrj }
3033*38fd1498Szrj 
3034*38fd1498Szrj /* Return true if load/store lanes optab OPTAB is supported for
3035*38fd1498Szrj    array type TYPES.first when the optimization type is OPT_TYPE.  */
3036*38fd1498Szrj 
3037*38fd1498Szrj static bool
multi_vector_optab_supported_p(convert_optab optab,tree_pair types,optimization_type opt_type)3038*38fd1498Szrj multi_vector_optab_supported_p (convert_optab optab, tree_pair types,
3039*38fd1498Szrj 				optimization_type opt_type)
3040*38fd1498Szrj {
3041*38fd1498Szrj   gcc_assert (TREE_CODE (types.first) == ARRAY_TYPE);
3042*38fd1498Szrj   machine_mode imode = TYPE_MODE (types.first);
3043*38fd1498Szrj   machine_mode vmode = TYPE_MODE (TREE_TYPE (types.first));
3044*38fd1498Szrj   return (convert_optab_handler (optab, imode, vmode, opt_type)
3045*38fd1498Szrj 	  != CODE_FOR_nothing);
3046*38fd1498Szrj }
3047*38fd1498Szrj 
3048*38fd1498Szrj #define direct_unary_optab_supported_p direct_optab_supported_p
3049*38fd1498Szrj #define direct_binary_optab_supported_p direct_optab_supported_p
3050*38fd1498Szrj #define direct_cond_unary_optab_supported_p direct_optab_supported_p
3051*38fd1498Szrj #define direct_cond_binary_optab_supported_p direct_optab_supported_p
3052*38fd1498Szrj #define direct_mask_load_optab_supported_p direct_optab_supported_p
3053*38fd1498Szrj #define direct_load_lanes_optab_supported_p multi_vector_optab_supported_p
3054*38fd1498Szrj #define direct_mask_load_lanes_optab_supported_p multi_vector_optab_supported_p
3055*38fd1498Szrj #define direct_gather_load_optab_supported_p direct_optab_supported_p
3056*38fd1498Szrj #define direct_mask_store_optab_supported_p direct_optab_supported_p
3057*38fd1498Szrj #define direct_store_lanes_optab_supported_p multi_vector_optab_supported_p
3058*38fd1498Szrj #define direct_mask_store_lanes_optab_supported_p multi_vector_optab_supported_p
3059*38fd1498Szrj #define direct_scatter_store_optab_supported_p direct_optab_supported_p
3060*38fd1498Szrj #define direct_while_optab_supported_p convert_optab_supported_p
3061*38fd1498Szrj #define direct_fold_extract_optab_supported_p direct_optab_supported_p
3062*38fd1498Szrj #define direct_fold_left_optab_supported_p direct_optab_supported_p
3063*38fd1498Szrj 
3064*38fd1498Szrj /* Return the optab used by internal function FN.  */
3065*38fd1498Szrj 
3066*38fd1498Szrj static optab
direct_internal_fn_optab(internal_fn fn,tree_pair types)3067*38fd1498Szrj direct_internal_fn_optab (internal_fn fn, tree_pair types)
3068*38fd1498Szrj {
3069*38fd1498Szrj   switch (fn)
3070*38fd1498Szrj     {
3071*38fd1498Szrj #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
3072*38fd1498Szrj     case IFN_##CODE: break;
3073*38fd1498Szrj #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
3074*38fd1498Szrj     case IFN_##CODE: return OPTAB##_optab;
3075*38fd1498Szrj #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
3076*38fd1498Szrj 				     UNSIGNED_OPTAB, TYPE)		\
3077*38fd1498Szrj     case IFN_##CODE: return (TYPE_UNSIGNED (types.SELECTOR)		\
3078*38fd1498Szrj 			     ? UNSIGNED_OPTAB ## _optab			\
3079*38fd1498Szrj 			     : SIGNED_OPTAB ## _optab);
3080*38fd1498Szrj #include "internal-fn.def"
3081*38fd1498Szrj 
3082*38fd1498Szrj     case IFN_LAST:
3083*38fd1498Szrj       break;
3084*38fd1498Szrj     }
3085*38fd1498Szrj   gcc_unreachable ();
3086*38fd1498Szrj }
3087*38fd1498Szrj 
3088*38fd1498Szrj /* Return the optab used by internal function FN.  */
3089*38fd1498Szrj 
3090*38fd1498Szrj static optab
direct_internal_fn_optab(internal_fn fn)3091*38fd1498Szrj direct_internal_fn_optab (internal_fn fn)
3092*38fd1498Szrj {
3093*38fd1498Szrj   switch (fn)
3094*38fd1498Szrj     {
3095*38fd1498Szrj #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
3096*38fd1498Szrj     case IFN_##CODE: break;
3097*38fd1498Szrj #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
3098*38fd1498Szrj     case IFN_##CODE: return OPTAB##_optab;
3099*38fd1498Szrj #include "internal-fn.def"
3100*38fd1498Szrj 
3101*38fd1498Szrj     case IFN_LAST:
3102*38fd1498Szrj       break;
3103*38fd1498Szrj     }
3104*38fd1498Szrj   gcc_unreachable ();
3105*38fd1498Szrj }
3106*38fd1498Szrj 
3107*38fd1498Szrj /* Return true if FN is supported for the types in TYPES when the
3108*38fd1498Szrj    optimization type is OPT_TYPE.  The types are those associated with
3109*38fd1498Szrj    the "type0" and "type1" fields of FN's direct_internal_fn_info
3110*38fd1498Szrj    structure.  */
3111*38fd1498Szrj 
3112*38fd1498Szrj bool
direct_internal_fn_supported_p(internal_fn fn,tree_pair types,optimization_type opt_type)3113*38fd1498Szrj direct_internal_fn_supported_p (internal_fn fn, tree_pair types,
3114*38fd1498Szrj 				optimization_type opt_type)
3115*38fd1498Szrj {
3116*38fd1498Szrj   switch (fn)
3117*38fd1498Szrj     {
3118*38fd1498Szrj #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
3119*38fd1498Szrj     case IFN_##CODE: break;
3120*38fd1498Szrj #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
3121*38fd1498Szrj     case IFN_##CODE: \
3122*38fd1498Szrj       return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types, \
3123*38fd1498Szrj 						opt_type);
3124*38fd1498Szrj #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
3125*38fd1498Szrj 				     UNSIGNED_OPTAB, TYPE)		\
3126*38fd1498Szrj     case IFN_##CODE:							\
3127*38fd1498Szrj       {									\
3128*38fd1498Szrj 	optab which_optab = (TYPE_UNSIGNED (types.SELECTOR)		\
3129*38fd1498Szrj 			     ? UNSIGNED_OPTAB ## _optab			\
3130*38fd1498Szrj 			     : SIGNED_OPTAB ## _optab);			\
3131*38fd1498Szrj 	return direct_##TYPE##_optab_supported_p (which_optab, types,	\
3132*38fd1498Szrj 						  opt_type);		\
3133*38fd1498Szrj       }
3134*38fd1498Szrj #include "internal-fn.def"
3135*38fd1498Szrj 
3136*38fd1498Szrj     case IFN_LAST:
3137*38fd1498Szrj       break;
3138*38fd1498Szrj     }
3139*38fd1498Szrj   gcc_unreachable ();
3140*38fd1498Szrj }
3141*38fd1498Szrj 
3142*38fd1498Szrj /* Return true if FN is supported for type TYPE when the optimization
3143*38fd1498Szrj    type is OPT_TYPE.  The caller knows that the "type0" and "type1"
3144*38fd1498Szrj    fields of FN's direct_internal_fn_info structure are the same.  */
3145*38fd1498Szrj 
3146*38fd1498Szrj bool
direct_internal_fn_supported_p(internal_fn fn,tree type,optimization_type opt_type)3147*38fd1498Szrj direct_internal_fn_supported_p (internal_fn fn, tree type,
3148*38fd1498Szrj 				optimization_type opt_type)
3149*38fd1498Szrj {
3150*38fd1498Szrj   const direct_internal_fn_info &info = direct_internal_fn (fn);
3151*38fd1498Szrj   gcc_checking_assert (info.type0 == info.type1);
3152*38fd1498Szrj   return direct_internal_fn_supported_p (fn, tree_pair (type, type), opt_type);
3153*38fd1498Szrj }
3154*38fd1498Szrj 
3155*38fd1498Szrj /* Return true if IFN_SET_EDOM is supported.  */
3156*38fd1498Szrj 
3157*38fd1498Szrj bool
set_edom_supported_p(void)3158*38fd1498Szrj set_edom_supported_p (void)
3159*38fd1498Szrj {
3160*38fd1498Szrj #ifdef TARGET_EDOM
3161*38fd1498Szrj   return true;
3162*38fd1498Szrj #else
3163*38fd1498Szrj   return false;
3164*38fd1498Szrj #endif
3165*38fd1498Szrj }
3166*38fd1498Szrj 
3167*38fd1498Szrj #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
3168*38fd1498Szrj   static void						\
3169*38fd1498Szrj   expand_##CODE (internal_fn fn, gcall *stmt)		\
3170*38fd1498Szrj   {							\
3171*38fd1498Szrj     expand_##TYPE##_optab_fn (fn, stmt, OPTAB##_optab);	\
3172*38fd1498Szrj   }
3173*38fd1498Szrj #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
3174*38fd1498Szrj 				     UNSIGNED_OPTAB, TYPE)		\
3175*38fd1498Szrj   static void								\
3176*38fd1498Szrj   expand_##CODE (internal_fn fn, gcall *stmt)				\
3177*38fd1498Szrj   {									\
3178*38fd1498Szrj     tree_pair types = direct_internal_fn_types (fn, stmt);		\
3179*38fd1498Szrj     optab which_optab = direct_internal_fn_optab (fn, types);		\
3180*38fd1498Szrj     expand_##TYPE##_optab_fn (fn, stmt, which_optab);			\
3181*38fd1498Szrj   }
3182*38fd1498Szrj #include "internal-fn.def"
3183*38fd1498Szrj 
3184*38fd1498Szrj /* Routines to expand each internal function, indexed by function number.
3185*38fd1498Szrj    Each routine has the prototype:
3186*38fd1498Szrj 
3187*38fd1498Szrj        expand_<NAME> (gcall *stmt)
3188*38fd1498Szrj 
3189*38fd1498Szrj    where STMT is the statement that performs the call. */
3190*38fd1498Szrj static void (*const internal_fn_expanders[]) (internal_fn, gcall *) = {
3191*38fd1498Szrj #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) expand_##CODE,
3192*38fd1498Szrj #include "internal-fn.def"
3193*38fd1498Szrj   0
3194*38fd1498Szrj };
3195*38fd1498Szrj 
3196*38fd1498Szrj /* Return a function that performs the conditional form of CODE, i.e.:
3197*38fd1498Szrj 
3198*38fd1498Szrj      LHS = RHS1 ? RHS2 CODE RHS3 : RHS2
3199*38fd1498Szrj 
3200*38fd1498Szrj    (operating elementwise if the operands are vectors).  Return IFN_LAST
3201*38fd1498Szrj    if no such function exists.  */
3202*38fd1498Szrj 
3203*38fd1498Szrj internal_fn
get_conditional_internal_fn(tree_code code)3204*38fd1498Szrj get_conditional_internal_fn (tree_code code)
3205*38fd1498Szrj {
3206*38fd1498Szrj   switch (code)
3207*38fd1498Szrj     {
3208*38fd1498Szrj     case PLUS_EXPR:
3209*38fd1498Szrj       return IFN_COND_ADD;
3210*38fd1498Szrj     case MINUS_EXPR:
3211*38fd1498Szrj       return IFN_COND_SUB;
3212*38fd1498Szrj     case MIN_EXPR:
3213*38fd1498Szrj       return IFN_COND_MIN;
3214*38fd1498Szrj     case MAX_EXPR:
3215*38fd1498Szrj       return IFN_COND_MAX;
3216*38fd1498Szrj     case BIT_AND_EXPR:
3217*38fd1498Szrj       return IFN_COND_AND;
3218*38fd1498Szrj     case BIT_IOR_EXPR:
3219*38fd1498Szrj       return IFN_COND_IOR;
3220*38fd1498Szrj     case BIT_XOR_EXPR:
3221*38fd1498Szrj       return IFN_COND_XOR;
3222*38fd1498Szrj     default:
3223*38fd1498Szrj       return IFN_LAST;
3224*38fd1498Szrj     }
3225*38fd1498Szrj }
3226*38fd1498Szrj 
3227*38fd1498Szrj /* Return true if IFN is some form of load from memory.  */
3228*38fd1498Szrj 
3229*38fd1498Szrj bool
internal_load_fn_p(internal_fn fn)3230*38fd1498Szrj internal_load_fn_p (internal_fn fn)
3231*38fd1498Szrj {
3232*38fd1498Szrj   switch (fn)
3233*38fd1498Szrj     {
3234*38fd1498Szrj     case IFN_MASK_LOAD:
3235*38fd1498Szrj     case IFN_LOAD_LANES:
3236*38fd1498Szrj     case IFN_MASK_LOAD_LANES:
3237*38fd1498Szrj     case IFN_GATHER_LOAD:
3238*38fd1498Szrj     case IFN_MASK_GATHER_LOAD:
3239*38fd1498Szrj       return true;
3240*38fd1498Szrj 
3241*38fd1498Szrj     default:
3242*38fd1498Szrj       return false;
3243*38fd1498Szrj     }
3244*38fd1498Szrj }
3245*38fd1498Szrj 
3246*38fd1498Szrj /* Return true if IFN is some form of store to memory.  */
3247*38fd1498Szrj 
3248*38fd1498Szrj bool
internal_store_fn_p(internal_fn fn)3249*38fd1498Szrj internal_store_fn_p (internal_fn fn)
3250*38fd1498Szrj {
3251*38fd1498Szrj   switch (fn)
3252*38fd1498Szrj     {
3253*38fd1498Szrj     case IFN_MASK_STORE:
3254*38fd1498Szrj     case IFN_STORE_LANES:
3255*38fd1498Szrj     case IFN_MASK_STORE_LANES:
3256*38fd1498Szrj     case IFN_SCATTER_STORE:
3257*38fd1498Szrj     case IFN_MASK_SCATTER_STORE:
3258*38fd1498Szrj       return true;
3259*38fd1498Szrj 
3260*38fd1498Szrj     default:
3261*38fd1498Szrj       return false;
3262*38fd1498Szrj     }
3263*38fd1498Szrj }
3264*38fd1498Szrj 
3265*38fd1498Szrj /* Return true if IFN is some form of gather load or scatter store.  */
3266*38fd1498Szrj 
3267*38fd1498Szrj bool
internal_gather_scatter_fn_p(internal_fn fn)3268*38fd1498Szrj internal_gather_scatter_fn_p (internal_fn fn)
3269*38fd1498Szrj {
3270*38fd1498Szrj   switch (fn)
3271*38fd1498Szrj     {
3272*38fd1498Szrj     case IFN_GATHER_LOAD:
3273*38fd1498Szrj     case IFN_MASK_GATHER_LOAD:
3274*38fd1498Szrj     case IFN_SCATTER_STORE:
3275*38fd1498Szrj     case IFN_MASK_SCATTER_STORE:
3276*38fd1498Szrj       return true;
3277*38fd1498Szrj 
3278*38fd1498Szrj     default:
3279*38fd1498Szrj       return false;
3280*38fd1498Szrj     }
3281*38fd1498Szrj }
3282*38fd1498Szrj 
3283*38fd1498Szrj /* If FN takes a vector mask argument, return the index of that argument,
3284*38fd1498Szrj    otherwise return -1.  */
3285*38fd1498Szrj 
3286*38fd1498Szrj int
internal_fn_mask_index(internal_fn fn)3287*38fd1498Szrj internal_fn_mask_index (internal_fn fn)
3288*38fd1498Szrj {
3289*38fd1498Szrj   switch (fn)
3290*38fd1498Szrj     {
3291*38fd1498Szrj     case IFN_MASK_LOAD:
3292*38fd1498Szrj     case IFN_MASK_LOAD_LANES:
3293*38fd1498Szrj     case IFN_MASK_STORE:
3294*38fd1498Szrj     case IFN_MASK_STORE_LANES:
3295*38fd1498Szrj       return 2;
3296*38fd1498Szrj 
3297*38fd1498Szrj     case IFN_MASK_GATHER_LOAD:
3298*38fd1498Szrj       return 3;
3299*38fd1498Szrj 
3300*38fd1498Szrj     case IFN_MASK_SCATTER_STORE:
3301*38fd1498Szrj       return 4;
3302*38fd1498Szrj 
3303*38fd1498Szrj     default:
3304*38fd1498Szrj       return -1;
3305*38fd1498Szrj     }
3306*38fd1498Szrj }
3307*38fd1498Szrj 
3308*38fd1498Szrj /* If FN takes a value that should be stored to memory, return the index
3309*38fd1498Szrj    of that argument, otherwise return -1.  */
3310*38fd1498Szrj 
3311*38fd1498Szrj int
internal_fn_stored_value_index(internal_fn fn)3312*38fd1498Szrj internal_fn_stored_value_index (internal_fn fn)
3313*38fd1498Szrj {
3314*38fd1498Szrj   switch (fn)
3315*38fd1498Szrj     {
3316*38fd1498Szrj     case IFN_MASK_STORE:
3317*38fd1498Szrj     case IFN_SCATTER_STORE:
3318*38fd1498Szrj     case IFN_MASK_SCATTER_STORE:
3319*38fd1498Szrj       return 3;
3320*38fd1498Szrj 
3321*38fd1498Szrj     default:
3322*38fd1498Szrj       return -1;
3323*38fd1498Szrj     }
3324*38fd1498Szrj }
3325*38fd1498Szrj 
3326*38fd1498Szrj /* Return true if the target supports gather load or scatter store function
3327*38fd1498Szrj    IFN.  For loads, VECTOR_TYPE is the vector type of the load result,
3328*38fd1498Szrj    while for stores it is the vector type of the stored data argument.
3329*38fd1498Szrj    MEMORY_ELEMENT_TYPE is the type of the memory elements being loaded
3330*38fd1498Szrj    or stored.  OFFSET_SIGN is the sign of the offset argument, which is
3331*38fd1498Szrj    only relevant when the offset is narrower than an address.  SCALE is
3332*38fd1498Szrj    the amount by which the offset should be multiplied *after* it has
3333*38fd1498Szrj    been extended to address width.  */
3334*38fd1498Szrj 
3335*38fd1498Szrj bool
internal_gather_scatter_fn_supported_p(internal_fn ifn,tree vector_type,tree memory_element_type,signop offset_sign,int scale)3336*38fd1498Szrj internal_gather_scatter_fn_supported_p (internal_fn ifn, tree vector_type,
3337*38fd1498Szrj 					tree memory_element_type,
3338*38fd1498Szrj 					signop offset_sign, int scale)
3339*38fd1498Szrj {
3340*38fd1498Szrj   if (!tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (vector_type)),
3341*38fd1498Szrj 			   TYPE_SIZE (memory_element_type)))
3342*38fd1498Szrj     return false;
3343*38fd1498Szrj   optab optab = direct_internal_fn_optab (ifn);
3344*38fd1498Szrj   insn_code icode = direct_optab_handler (optab, TYPE_MODE (vector_type));
3345*38fd1498Szrj   int output_ops = internal_load_fn_p (ifn) ? 1 : 0;
3346*38fd1498Szrj   return (icode != CODE_FOR_nothing
3347*38fd1498Szrj 	  && insn_operand_matches (icode, 2 + output_ops,
3348*38fd1498Szrj 				   GEN_INT (offset_sign == UNSIGNED))
3349*38fd1498Szrj 	  && insn_operand_matches (icode, 3 + output_ops,
3350*38fd1498Szrj 				   GEN_INT (scale)));
3351*38fd1498Szrj }
3352*38fd1498Szrj 
3353*38fd1498Szrj /* Expand STMT as though it were a call to internal function FN.  */
3354*38fd1498Szrj 
3355*38fd1498Szrj void
expand_internal_call(internal_fn fn,gcall * stmt)3356*38fd1498Szrj expand_internal_call (internal_fn fn, gcall *stmt)
3357*38fd1498Szrj {
3358*38fd1498Szrj   internal_fn_expanders[fn] (fn, stmt);
3359*38fd1498Szrj }
3360*38fd1498Szrj 
3361*38fd1498Szrj /* Expand STMT, which is a call to internal function FN.  */
3362*38fd1498Szrj 
3363*38fd1498Szrj void
expand_internal_call(gcall * stmt)3364*38fd1498Szrj expand_internal_call (gcall *stmt)
3365*38fd1498Szrj {
3366*38fd1498Szrj   expand_internal_call (gimple_call_internal_fn (stmt), stmt);
3367*38fd1498Szrj }
3368*38fd1498Szrj 
3369*38fd1498Szrj void
expand_PHI(internal_fn,gcall *)3370*38fd1498Szrj expand_PHI (internal_fn, gcall *)
3371*38fd1498Szrj {
3372*38fd1498Szrj     gcc_unreachable ();
3373*38fd1498Szrj }
3374