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 "ient, &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