summaryrefslogtreecommitdiff
path: root/gcc/wide-int-range.h
blob: 7fbdffd84b311bf75b0f71fca71a7ff1b326002b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/* Support routines for range operations on wide ints.
   Copyright (C) 2018-2019 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#ifndef GCC_WIDE_INT_RANGE_H
#define GCC_WIDE_INT_RANGE_H

extern bool wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub,
					  enum tree_code code, signop sign,
					  const wide_int &, const wide_int &,
					  const wide_int &, const wide_int &,
					  bool overflow_undefined);
extern bool wide_int_range_mult_wrapping (wide_int &res_lb,
					  wide_int &res_ub,
					  signop sign,
					  unsigned prec,
					  const wide_int &min0_,
					  const wide_int &max0_,
					  const wide_int &min1_,
					  const wide_int &max1_);
extern bool wide_int_range_multiplicative_op (wide_int &res_lb,
					      wide_int &res_ub,
					      enum tree_code code,
					      signop sign,
					      unsigned prec,
					      const wide_int &vr0_lb,
					      const wide_int &vr0_ub,
					      const wide_int &vr1_lb,
					      const wide_int &vr1_ub,
					      bool overflow_undefined);
extern bool wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub,
				   signop sign, unsigned prec,
				   const wide_int &, const wide_int &,
				   const wide_int &, const wide_int &,
				   bool overflow_undefined);
extern void wide_int_range_set_zero_nonzero_bits (signop,
						  const wide_int &lb,
						  const wide_int &ub,
						  wide_int &may_be_nonzero,
						  wide_int &must_be_nonzero);
extern bool wide_int_range_optimize_bit_op (wide_int &res_lb, wide_int &res_ub,
					    enum tree_code code,
					    signop sign,
					    const wide_int &vr0_lb,
					    const wide_int &vr0_ub,
					    const wide_int &vr1_lb,
					    const wide_int &vr1_ub);
extern bool wide_int_range_get_mask_and_bounds (wide_int &mask,
						wide_int &lower_bound,
						wide_int &upper_bound,
						const wide_int &vr0_min,
						const wide_int &vr0_max,
						const wide_int &vr1_min,
						const wide_int &vr1_max);
extern bool wide_int_range_bit_xor (wide_int &wmin, wide_int &wmax,
				    signop sign,
				    unsigned prec,
				    const wide_int &must_be_nonzero0,
				    const wide_int &may_be_nonzero0,
				    const wide_int &must_be_nonzero1,
				    const wide_int &may_be_nonzero1);
extern bool wide_int_range_bit_ior (wide_int &wmin, wide_int &wmax,
				    signop sign,
				    const wide_int &vr0_min,
				    const wide_int &vr0_max,
				    const wide_int &vr1_min,
				    const wide_int &vr1_max,
				    const wide_int &must_be_nonzero0,
				    const wide_int &may_be_nonzero0,
				    const wide_int &must_be_nonzero1,
				    const wide_int &may_be_nonzero1);
extern bool wide_int_range_bit_and (wide_int &wmin, wide_int &wmax,
				    signop sign,
				    unsigned prec,
				    const wide_int &vr0_min,
				    const wide_int &vr0_max,
				    const wide_int &vr1_min,
				    const wide_int &vr1_max,
				    const wide_int &must_be_nonzero0,
				    const wide_int &may_be_nonzero0,
				    const wide_int &must_be_nonzero1,
				    const wide_int &may_be_nonzero1);
extern void wide_int_range_trunc_mod (wide_int &wmin, wide_int &wmax,
				      signop sign,
				      unsigned prec,
				      const wide_int &vr0_min,
				      const wide_int &vr0_max,
				      const wide_int &vr1_min,
				      const wide_int &vr1_max);
extern bool wide_int_range_abs (wide_int &min, wide_int &max,
				signop sign, unsigned prec,
				const wide_int &vr0_min,
				const wide_int &vr0_max,
				bool overflow_undefined);
extern bool wide_int_range_convert (wide_int &min, wide_int &max,
				    signop inner_sign,
				    unsigned inner_prec,
				    signop outer_sign,
				    unsigned outer_prec,
				    const wide_int &vr0_min,
				    const wide_int &vr0_max);
extern bool wide_int_range_div (wide_int &wmin, wide_int &wmax,
				enum tree_code code,
				signop sign, unsigned prec,
				const wide_int &dividend_min,
				const wide_int &dividend_max,
				const wide_int &divisor_min,
				const wide_int &divisor_max,
				bool overflow_undefined,
				bool &extra_range_p,
				wide_int &extra_min, wide_int &extra_max);

/* Return TRUE if shifting by range [MIN, MAX] is undefined behavior,
   interpreting MIN and MAX according to SIGN.  */

inline bool
wide_int_range_shift_undefined_p (signop sign, unsigned prec,
				  const wide_int &min, const wide_int &max)
{
  /* ?? Note: The original comment said this only applied to
     RSHIFT_EXPR, but it was being applied to both left and right
     shifts.  */

  /* Shifting by any values outside [0..prec-1], gets undefined
     behavior from the shift operation.  We cannot even trust
     SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl
     shifts, and the operation at the tree level may be widened.  */
  return wi::lt_p (min, 0, sign) || wi::ge_p (max, prec, sign);
}

/* Calculate MIN/MAX_EXPR of two ranges and store the result in [MIN, MAX].  */

inline bool
wide_int_range_min_max (wide_int &min, wide_int &max,
			tree_code code,
			signop sign, unsigned prec,
			const wide_int &vr0_min, const wide_int &vr0_max,
			const wide_int &vr1_min, const wide_int &vr1_max)
{
  wi::overflow_type overflow;
  wide_int_binop (min, code, vr0_min, vr1_min, sign, &overflow);
  wide_int_binop (max, code, vr0_max, vr1_max, sign, &overflow);
  /* If the new range covers the entire domain, that's really no range
     at all.  */
  if (min == wi::min_value (prec, sign)
      && max == wi::max_value (prec, sign))
    return false;
  return true;
}

/* Return TRUE if 0 is within [WMIN, WMAX].  */

inline bool
wide_int_range_includes_zero_p (const wide_int &wmin, const wide_int &wmax,
				signop sign)
{
  return wi::le_p (wmin, 0, sign) && wi::ge_p (wmax, 0, sign);
}

/* Return TRUE if [WMIN, WMAX] is the singleton 0.  */

inline bool
wide_int_range_zero_p (const wide_int &wmin, const wide_int &wmax,
		       unsigned prec)
{
  return wmin == wmax && wi::eq_p (wmin, wi::zero (prec));
}

#endif /* GCC_WIDE_INT_RANGE_H */