]>
Commit | Line | Data |
---|---|---|
51ce0638 AM |
1 | /* Code for GIMPLE range op related routines. |
2 | Copyright (C) 2019-2022 Free Software Foundation, Inc. | |
3 | Contributed by Andrew MacLeod <amacleod@redhat.com> | |
4 | and Aldy Hernandez <aldyh@redhat.com>. | |
5 | ||
6 | This file is part of GCC. | |
7 | ||
8 | GCC is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 3, or (at your option) | |
11 | any later version. | |
12 | ||
13 | GCC is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GCC; see the file COPYING3. If not see | |
20 | <http://www.gnu.org/licenses/>. */ | |
21 | ||
22 | #include "config.h" | |
23 | #include "system.h" | |
24 | #include "coretypes.h" | |
25 | #include "backend.h" | |
26 | #include "insn-codes.h" | |
27 | #include "tree.h" | |
28 | #include "gimple.h" | |
29 | #include "ssa.h" | |
30 | #include "gimple-pretty-print.h" | |
31 | #include "optabs-tree.h" | |
32 | #include "gimple-iterator.h" | |
33 | #include "gimple-fold.h" | |
34 | #include "wide-int.h" | |
35 | #include "fold-const.h" | |
36 | #include "case-cfn-macros.h" | |
37 | #include "omp-general.h" | |
38 | #include "cfgloop.h" | |
39 | #include "tree-ssa-loop.h" | |
40 | #include "tree-scalar-evolution.h" | |
41 | #include "langhooks.h" | |
42 | #include "vr-values.h" | |
43 | #include "range.h" | |
44 | #include "value-query.h" | |
45 | #include "gimple-range.h" | |
46 | ||
47 | // Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names | |
48 | // on the statement. For efficiency, it is an error to not pass in enough | |
49 | // elements for the vector. Return the number of ssa-names. | |
50 | ||
51 | unsigned | |
52 | gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt) | |
53 | { | |
54 | tree ssa; | |
55 | int count = 0; | |
56 | ||
57 | gimple_range_op_handler handler (stmt); | |
58 | if (handler) | |
59 | { | |
60 | gcc_checking_assert (vec_size >= 2); | |
61 | if ((ssa = gimple_range_ssa_p (handler.operand1 ()))) | |
62 | vec[count++] = ssa; | |
63 | if ((ssa = gimple_range_ssa_p (handler.operand2 ()))) | |
64 | vec[count++] = ssa; | |
65 | } | |
66 | else if (is_a<gassign *> (stmt) | |
67 | && gimple_assign_rhs_code (stmt) == COND_EXPR) | |
68 | { | |
69 | gcc_checking_assert (vec_size >= 3); | |
70 | gassign *st = as_a<gassign *> (stmt); | |
71 | if ((ssa = gimple_range_ssa_p (gimple_assign_rhs1 (st)))) | |
72 | vec[count++] = ssa; | |
73 | if ((ssa = gimple_range_ssa_p (gimple_assign_rhs2 (st)))) | |
74 | vec[count++] = ssa; | |
75 | if ((ssa = gimple_range_ssa_p (gimple_assign_rhs3 (st)))) | |
76 | vec[count++] = ssa; | |
77 | } | |
78 | return count; | |
79 | } | |
80 | ||
81 | // Return the base of the RHS of an assignment. | |
82 | ||
83 | static tree | |
84 | gimple_range_base_of_assignment (const gimple *stmt) | |
85 | { | |
86 | gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN); | |
87 | tree op1 = gimple_assign_rhs1 (stmt); | |
88 | if (gimple_assign_rhs_code (stmt) == ADDR_EXPR) | |
89 | return get_base_address (TREE_OPERAND (op1, 0)); | |
90 | return op1; | |
91 | } | |
92 | ||
93 | // If statement is supported by range-ops, set the CODE and return the TYPE. | |
94 | ||
95 | static tree | |
96 | get_code_and_type (gimple *s, enum tree_code &code) | |
97 | { | |
98 | tree type = NULL_TREE; | |
99 | code = NOP_EXPR; | |
100 | ||
101 | if (const gassign *ass = dyn_cast<const gassign *> (s)) | |
102 | { | |
103 | code = gimple_assign_rhs_code (ass); | |
104 | // The LHS of a comparison is always an int, so we must look at | |
105 | // the operands. | |
106 | if (TREE_CODE_CLASS (code) == tcc_comparison) | |
107 | type = TREE_TYPE (gimple_assign_rhs1 (ass)); | |
108 | else | |
109 | type = TREE_TYPE (gimple_assign_lhs (ass)); | |
110 | } | |
111 | else if (const gcond *cond = dyn_cast<const gcond *> (s)) | |
112 | { | |
113 | code = gimple_cond_code (cond); | |
114 | type = TREE_TYPE (gimple_cond_lhs (cond)); | |
115 | } | |
116 | return type; | |
117 | } | |
118 | ||
119 | // If statement S has a supported range_op handler return TRUE. | |
120 | ||
121 | bool | |
122 | gimple_range_op_handler::supported_p (gimple *s) | |
123 | { | |
124 | enum tree_code code; | |
125 | tree type = get_code_and_type (s, code); | |
b40b3035 AM |
126 | if (type && range_op_handler (code, type)) |
127 | return true; | |
128 | if (is_a <gcall *> (s) && gimple_range_op_handler (s)) | |
129 | return true; | |
130 | return false; | |
51ce0638 AM |
131 | } |
132 | ||
133 | // Construct a handler object for statement S. | |
134 | ||
135 | gimple_range_op_handler::gimple_range_op_handler (gimple *s) | |
136 | { | |
137 | enum tree_code code; | |
138 | tree type = get_code_and_type (s, code); | |
139 | m_stmt = s; | |
b40b3035 AM |
140 | m_op1 = NULL_TREE; |
141 | m_op2 = NULL_TREE; | |
51ce0638 AM |
142 | if (type) |
143 | set_op_handler (code, type); | |
144 | ||
145 | if (m_valid) | |
146 | switch (gimple_code (m_stmt)) | |
147 | { | |
148 | case GIMPLE_COND: | |
149 | m_op1 = gimple_cond_lhs (m_stmt); | |
150 | m_op2 = gimple_cond_rhs (m_stmt); | |
b40b3035 | 151 | return; |
51ce0638 AM |
152 | case GIMPLE_ASSIGN: |
153 | m_op1 = gimple_range_base_of_assignment (m_stmt); | |
154 | if (m_op1 && TREE_CODE (m_op1) == MEM_REF) | |
155 | { | |
156 | // If the base address is an SSA_NAME, we return it | |
157 | // here. This allows processing of the range of that | |
158 | // name, while the rest of the expression is simply | |
159 | // ignored. The code in range_ops will see the | |
160 | // ADDR_EXPR and do the right thing. | |
161 | tree ssa = TREE_OPERAND (m_op1, 0); | |
162 | if (TREE_CODE (ssa) == SSA_NAME) | |
163 | m_op1 = ssa; | |
164 | } | |
165 | if (gimple_num_ops (m_stmt) >= 3) | |
166 | m_op2 = gimple_assign_rhs2 (m_stmt); | |
b40b3035 | 167 | return; |
51ce0638 | 168 | default: |
b40b3035 AM |
169 | gcc_unreachable (); |
170 | return; | |
51ce0638 | 171 | } |
b40b3035 AM |
172 | // If no range-op table entry handled this stmt, check for other supported |
173 | // statements. | |
174 | if (is_a <gcall *> (m_stmt)) | |
175 | maybe_builtin_call (); | |
51ce0638 AM |
176 | } |
177 | ||
178 | // Calculate what we can determine of the range of this unary | |
179 | // statement's operand if the lhs of the expression has the range | |
180 | // LHS_RANGE. Return false if nothing can be determined. | |
181 | ||
182 | bool | |
183 | gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range) | |
184 | { | |
185 | gcc_checking_assert (gimple_num_ops (m_stmt) < 3); | |
186 | // Give up on empty ranges. | |
187 | if (lhs_range.undefined_p ()) | |
188 | return false; | |
189 | ||
190 | // Unary operations require the type of the first operand in the | |
191 | // second range position. | |
192 | tree type = TREE_TYPE (operand1 ()); | |
193 | Value_Range type_range (type); | |
194 | type_range.set_varying (type); | |
195 | return op1_range (r, type, lhs_range, type_range); | |
196 | } | |
197 | ||
198 | // Calculate what we can determine of the range of this statement's | |
199 | // first operand if the lhs of the expression has the range LHS_RANGE | |
200 | // and the second operand has the range OP2_RANGE. Return false if | |
201 | // nothing can be determined. | |
202 | ||
203 | bool | |
204 | gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range, | |
205 | const vrange &op2_range) | |
206 | { | |
207 | // Give up on empty ranges. | |
208 | if (lhs_range.undefined_p ()) | |
209 | return false; | |
210 | ||
211 | // Unary operation are allowed to pass a range in for second operand | |
212 | // as there are often additional restrictions beyond the type which | |
213 | // can be imposed. See operator_cast::op1_range(). | |
214 | tree type = TREE_TYPE (operand1 ()); | |
215 | // If op2 is undefined, solve as if it is varying. | |
216 | if (op2_range.undefined_p ()) | |
217 | { | |
51ce0638 AM |
218 | if (gimple_num_ops (m_stmt) < 3) |
219 | return false; | |
a7a6649f AM |
220 | tree op2_type; |
221 | // This is sometimes invoked on single operand stmts. | |
222 | if (operand2 ()) | |
223 | op2_type = TREE_TYPE (operand2 ()); | |
224 | else | |
225 | op2_type = TREE_TYPE (operand1 ()); | |
51ce0638 AM |
226 | Value_Range trange (op2_type); |
227 | trange.set_varying (op2_type); | |
228 | return op1_range (r, type, lhs_range, trange); | |
229 | } | |
230 | return op1_range (r, type, lhs_range, op2_range); | |
231 | } | |
232 | ||
233 | // Calculate what we can determine of the range of this statement's | |
234 | // second operand if the lhs of the expression has the range LHS_RANGE | |
235 | // and the first operand has the range OP1_RANGE. Return false if | |
236 | // nothing can be determined. | |
237 | ||
238 | bool | |
239 | gimple_range_op_handler::calc_op2 (vrange &r, const vrange &lhs_range, | |
240 | const vrange &op1_range) | |
241 | { | |
242 | // Give up on empty ranges. | |
243 | if (lhs_range.undefined_p ()) | |
244 | return false; | |
245 | ||
246 | tree type = TREE_TYPE (operand2 ()); | |
247 | // If op1 is undefined, solve as if it is varying. | |
248 | if (op1_range.undefined_p ()) | |
249 | { | |
250 | tree op1_type = TREE_TYPE (operand1 ()); | |
251 | Value_Range trange (op1_type); | |
252 | trange.set_varying (op1_type); | |
253 | return op2_range (r, type, lhs_range, trange); | |
254 | } | |
255 | return op2_range (r, type, lhs_range, op1_range); | |
256 | } | |
b40b3035 AM |
257 | |
258 | // -------------------------------------------------------------------- | |
259 | ||
260 | // Implement range operator for float CFN_BUILT_IN_CONSTANT_P. | |
261 | class cfn_constant_float_p : public range_operator_float | |
262 | { | |
263 | public: | |
264 | using range_operator_float::fold_range; | |
265 | virtual bool fold_range (irange &r, tree type, const frange &lh, | |
266 | const irange &, relation_kind) const | |
267 | { | |
268 | if (lh.singleton_p ()) | |
269 | { | |
270 | r.set (build_one_cst (type), build_one_cst (type)); | |
271 | return true; | |
272 | } | |
273 | if (cfun->after_inlining) | |
274 | { | |
275 | r.set_zero (type); | |
276 | return true; | |
277 | } | |
278 | return false; | |
279 | } | |
280 | } op_cfn_constant_float_p; | |
281 | ||
282 | // Implement range operator for integral CFN_BUILT_IN_CONSTANT_P. | |
283 | class cfn_constant_p : public range_operator | |
284 | { | |
285 | public: | |
286 | using range_operator::fold_range; | |
287 | virtual bool fold_range (irange &r, tree type, const irange &lh, | |
288 | const irange &, relation_kind) const | |
289 | { | |
290 | if (lh.singleton_p ()) | |
291 | { | |
292 | r.set (build_one_cst (type), build_one_cst (type)); | |
293 | return true; | |
294 | } | |
295 | if (cfun->after_inlining) | |
296 | { | |
297 | r.set_zero (type); | |
298 | return true; | |
299 | } | |
300 | return false; | |
301 | } | |
302 | } op_cfn_constant_p; | |
303 | ||
eb82b9f6 AM |
304 | // Implement range operator for CFN_BUILT_IN_SIGNBIT. |
305 | class cfn_signbit : public range_operator_float | |
306 | { | |
307 | public: | |
308 | using range_operator_float::fold_range; | |
309 | virtual bool fold_range (irange &r, tree type, const frange &lh, | |
310 | const irange &, relation_kind) const | |
311 | { | |
312 | bool signbit; | |
313 | if (lh.signbit_p (signbit)) | |
314 | { | |
315 | if (signbit) | |
316 | r.set_nonzero (type); | |
317 | else | |
318 | r.set_zero (type); | |
319 | return true; | |
320 | } | |
321 | return false; | |
322 | } | |
323 | } op_cfn_signbit; | |
324 | ||
2f5da730 AM |
325 | // Implement range operator for CFN_BUILT_IN_TOUPPER and CFN_BUILT_IN_TOLOWER. |
326 | class cfn_toupper_tolower : public range_operator | |
327 | { | |
328 | public: | |
329 | using range_operator::fold_range; | |
330 | cfn_toupper_tolower (bool toupper) { m_toupper = toupper; } | |
331 | virtual bool fold_range (irange &r, tree type, const irange &lh, | |
332 | const irange &, relation_kind) const; | |
333 | private: | |
334 | bool get_letter_range (tree type, irange &lowers, irange &uppers) const; | |
335 | bool m_toupper; | |
336 | } op_cfn_toupper (true), op_cfn_tolower (false); | |
337 | ||
338 | // Return TRUE if we recognize the target character set and return the | |
339 | // range for lower case and upper case letters. | |
340 | ||
341 | bool | |
342 | cfn_toupper_tolower::get_letter_range (tree type, irange &lowers, | |
343 | irange &uppers) const | |
344 | { | |
345 | // ASCII | |
346 | int a = lang_hooks.to_target_charset ('a'); | |
347 | int z = lang_hooks.to_target_charset ('z'); | |
348 | int A = lang_hooks.to_target_charset ('A'); | |
349 | int Z = lang_hooks.to_target_charset ('Z'); | |
350 | ||
351 | if ((z - a == 25) && (Z - A == 25)) | |
352 | { | |
353 | lowers = int_range<2> (build_int_cst (type, a), build_int_cst (type, z)); | |
354 | uppers = int_range<2> (build_int_cst (type, A), build_int_cst (type, Z)); | |
355 | return true; | |
356 | } | |
357 | // Unknown character set. | |
358 | return false; | |
359 | } | |
360 | ||
361 | bool | |
362 | cfn_toupper_tolower::fold_range (irange &r, tree type, const irange &lh, | |
363 | const irange &, relation_kind) const | |
364 | { | |
365 | int_range<3> lowers; | |
366 | int_range<3> uppers; | |
367 | if (!get_letter_range (type, lowers, uppers)) | |
368 | return false; | |
369 | ||
370 | r = lh; | |
371 | if (m_toupper) | |
372 | { | |
373 | // Return the range passed in without any lower case characters, | |
374 | // but including all the upper case ones. | |
375 | lowers.invert (); | |
376 | r.intersect (lowers); | |
377 | r.union_ (uppers); | |
378 | } | |
379 | else | |
380 | { | |
381 | // Return the range passed in without any lower case characters, | |
382 | // but including all the upper case ones. | |
383 | uppers.invert (); | |
384 | r.intersect (uppers); | |
385 | r.union_ (lowers); | |
386 | } | |
387 | return true; | |
388 | } | |
389 | ||
b40b3035 AM |
390 | // Set up a gimple_range_op_handler for any built in function which can be |
391 | // supported via range-ops. | |
392 | ||
393 | void | |
394 | gimple_range_op_handler::maybe_builtin_call () | |
395 | { | |
396 | gcc_checking_assert (is_a <gcall *> (m_stmt)); | |
397 | ||
398 | gcall *call = as_a <gcall *> (m_stmt); | |
399 | combined_fn func = gimple_call_combined_fn (call); | |
400 | if (func == CFN_LAST) | |
401 | return; | |
402 | tree type = gimple_range_type (call); | |
403 | gcc_checking_assert (type); | |
404 | if (!Value_Range::supports_type_p (type)) | |
405 | return; | |
406 | ||
407 | switch (func) | |
408 | { | |
409 | case CFN_BUILT_IN_CONSTANT_P: | |
410 | m_op1 = gimple_call_arg (call, 0); | |
411 | m_valid = true; | |
412 | if (irange::supports_p (TREE_TYPE (m_op1))) | |
413 | m_int = &op_cfn_constant_p; | |
414 | else if (frange::supports_p (TREE_TYPE (m_op1))) | |
415 | m_float = &op_cfn_constant_float_p; | |
416 | else | |
417 | m_valid = false; | |
418 | break; | |
419 | ||
eb82b9f6 AM |
420 | case CFN_BUILT_IN_SIGNBIT: |
421 | m_op1 = gimple_call_arg (call, 0); | |
422 | m_float = &op_cfn_signbit; | |
423 | m_valid = true; | |
424 | break; | |
425 | ||
2f5da730 AM |
426 | case CFN_BUILT_IN_TOUPPER: |
427 | case CFN_BUILT_IN_TOLOWER: | |
428 | // Only proceed If the argument is compatible with the LHS. | |
429 | m_op1 = gimple_call_arg (call, 0); | |
430 | if (range_compatible_p (type, TREE_TYPE (m_op1))) | |
431 | { | |
432 | m_valid = true; | |
433 | m_int = (func == CFN_BUILT_IN_TOLOWER) ? &op_cfn_tolower | |
434 | : &op_cfn_toupper; | |
435 | } | |
436 | break; | |
437 | ||
b40b3035 AM |
438 | default: |
439 | break; | |
440 | } | |
441 | } |