]> git.ipfire.org Git - people/ms/gcc.git/blame - gcc/gimple-range-op.cc
Convert CFN_BUILT_IN_TOUPPER and TOLOWER to range-ops.
[people/ms/gcc.git] / gcc / gimple-range-op.cc
CommitLineData
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
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 3, or (at your option)
11any later version.
12
13GCC is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along 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
51unsigned
52gimple_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
83static tree
84gimple_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
95static tree
96get_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
121bool
122gimple_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
135gimple_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
182bool
183gimple_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
203bool
204gimple_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
238bool
239gimple_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.
261class cfn_constant_float_p : public range_operator_float
262{
263public:
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.
283class cfn_constant_p : public range_operator
284{
285public:
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.
305class cfn_signbit : public range_operator_float
306{
307public:
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.
326class cfn_toupper_tolower : public range_operator
327{
328public:
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;
333private:
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
341bool
342cfn_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
361bool
362cfn_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
393void
394gimple_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}