annotate gcc/internal-fn.c @ 132:d34655255c78

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