xref: /netbsd-src/external/gpl3/gcc/dist/gcc/fold-const-call.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* Constant folding for calls to built-in and internal functions.
2    Copyright (C) 1988-2022 Free Software Foundation, Inc.
3 
4 This file is part of GCC.
5 
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10 
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19 
20 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "realmpfr.h"
24 #include "tree.h"
25 #include "stor-layout.h"
26 #include "options.h"
27 #include "fold-const.h"
28 #include "fold-const-call.h"
29 #include "case-cfn-macros.h"
30 #include "tm.h" /* For C[LT]Z_DEFINED_AT_ZERO.  */
31 #include "builtins.h"
32 #include "gimple-expr.h"
33 #include "tree-vector-builder.h"
34 
35 /* Functions that test for certain constant types, abstracting away the
36    decision about whether to check for overflow.  */
37 
38 static inline bool
integer_cst_p(tree t)39 integer_cst_p (tree t)
40 {
41   return TREE_CODE (t) == INTEGER_CST && !TREE_OVERFLOW (t);
42 }
43 
44 static inline bool
real_cst_p(tree t)45 real_cst_p (tree t)
46 {
47   return TREE_CODE (t) == REAL_CST && !TREE_OVERFLOW (t);
48 }
49 
50 static inline bool
complex_cst_p(tree t)51 complex_cst_p (tree t)
52 {
53   return TREE_CODE (t) == COMPLEX_CST;
54 }
55 
56 /* Return true if ARG is a size_type_node constant.
57    Store it in *SIZE_OUT if so.  */
58 
59 static inline bool
size_t_cst_p(tree t,unsigned HOST_WIDE_INT * size_out)60 size_t_cst_p (tree t, unsigned HOST_WIDE_INT *size_out)
61 {
62   if (types_compatible_p (size_type_node, TREE_TYPE (t))
63       && integer_cst_p (t)
64       && tree_fits_uhwi_p (t))
65     {
66       *size_out = tree_to_uhwi (t);
67       return true;
68     }
69   return false;
70 }
71 
72 /* RES is the result of a comparison in which < 0 means "less", 0 means
73    "equal" and > 0 means "more".  Canonicalize it to -1, 0 or 1 and
74    return it in type TYPE.  */
75 
76 tree
build_cmp_result(tree type,int res)77 build_cmp_result (tree type, int res)
78 {
79   return build_int_cst (type, res < 0 ? -1 : res > 0 ? 1 : 0);
80 }
81 
82 /* M is the result of trying to constant-fold an expression (starting
83    with clear MPFR flags) and INEXACT says whether the result in M is
84    exact or inexact.  Return true if M can be used as a constant-folded
85    result in format FORMAT, storing the value in *RESULT if so.  */
86 
87 static bool
do_mpfr_ckconv(real_value * result,mpfr_srcptr m,bool inexact,const real_format * format)88 do_mpfr_ckconv (real_value *result, mpfr_srcptr m, bool inexact,
89 		const real_format *format)
90 {
91   /* Proceed iff we get a normal number, i.e. not NaN or Inf and no
92      overflow/underflow occurred.  If -frounding-math, proceed iff the
93      result of calling FUNC was exact.  */
94   if (!mpfr_number_p (m)
95       || mpfr_overflow_p ()
96       || mpfr_underflow_p ()
97       || (flag_rounding_math && inexact))
98     return false;
99 
100   REAL_VALUE_TYPE tmp;
101   real_from_mpfr (&tmp, m, format, MPFR_RNDN);
102 
103   /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR values.
104      If the REAL_VALUE_TYPE is zero but the mpft_t is not, then we
105      underflowed in the conversion.  */
106   if (!real_isfinite (&tmp)
107       || ((tmp.cl == rvc_zero) != (mpfr_zero_p (m) != 0)))
108     return false;
109 
110   real_convert (result, format, &tmp);
111   return real_identical (result, &tmp);
112 }
113 
114 /* Try to evaluate:
115 
116       *RESULT = f (*ARG)
117 
118    in format FORMAT, given that FUNC is the MPFR implementation of f.
119    Return true on success.  */
120 
121 static bool
do_mpfr_arg1(real_value * result,int (* func)(mpfr_ptr,mpfr_srcptr,mpfr_rnd_t),const real_value * arg,const real_format * format)122 do_mpfr_arg1 (real_value *result,
123 	      int (*func) (mpfr_ptr, mpfr_srcptr, mpfr_rnd_t),
124 	      const real_value *arg, const real_format *format)
125 {
126   /* To proceed, MPFR must exactly represent the target floating point
127      format, which only happens when the target base equals two.  */
128   if (format->b != 2 || !real_isfinite (arg))
129     return false;
130 
131   int prec = format->p;
132   mpfr_rnd_t rnd = format->round_towards_zero ? MPFR_RNDZ : MPFR_RNDN;
133   mpfr_t m;
134 
135   mpfr_init2 (m, prec);
136   mpfr_from_real (m, arg, MPFR_RNDN);
137   mpfr_clear_flags ();
138   bool inexact = func (m, m, rnd);
139   bool ok = do_mpfr_ckconv (result, m, inexact, format);
140   mpfr_clear (m);
141 
142   return ok;
143 }
144 
145 /* Try to evaluate:
146 
147       *RESULT_SIN = sin (*ARG);
148       *RESULT_COS = cos (*ARG);
149 
150    for format FORMAT.  Return true on success.  */
151 
152 static bool
do_mpfr_sincos(real_value * result_sin,real_value * result_cos,const real_value * arg,const real_format * format)153 do_mpfr_sincos (real_value *result_sin, real_value *result_cos,
154 		const real_value *arg, const real_format *format)
155 {
156   /* To proceed, MPFR must exactly represent the target floating point
157      format, which only happens when the target base equals two.  */
158   if (format->b != 2 || !real_isfinite (arg))
159     return false;
160 
161   int prec = format->p;
162   mpfr_rnd_t rnd = format->round_towards_zero ? MPFR_RNDZ : MPFR_RNDN;
163   mpfr_t m, ms, mc;
164 
165   mpfr_inits2 (prec, m, ms, mc, NULL);
166   mpfr_from_real (m, arg, MPFR_RNDN);
167   mpfr_clear_flags ();
168   bool inexact = mpfr_sin_cos (ms, mc, m, rnd);
169   bool ok = (do_mpfr_ckconv (result_sin, ms, inexact, format)
170 	     && do_mpfr_ckconv (result_cos, mc, inexact, format));
171   mpfr_clears (m, ms, mc, NULL);
172 
173   return ok;
174 }
175 
176 /* Try to evaluate:
177 
178       *RESULT = f (*ARG0, *ARG1)
179 
180    in format FORMAT, given that FUNC is the MPFR implementation of f.
181    Return true on success.  */
182 
183 static bool
do_mpfr_arg2(real_value * result,int (* func)(mpfr_ptr,mpfr_srcptr,mpfr_srcptr,mpfr_rnd_t),const real_value * arg0,const real_value * arg1,const real_format * format)184 do_mpfr_arg2 (real_value *result,
185 	      int (*func) (mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_rnd_t),
186 	      const real_value *arg0, const real_value *arg1,
187 	      const real_format *format)
188 {
189   /* To proceed, MPFR must exactly represent the target floating point
190      format, which only happens when the target base equals two.  */
191   if (format->b != 2 || !real_isfinite (arg0) || !real_isfinite (arg1))
192     return false;
193 
194   int prec = format->p;
195   mpfr_rnd_t rnd = format->round_towards_zero ? MPFR_RNDZ : MPFR_RNDN;
196   mpfr_t m0, m1;
197 
198   mpfr_inits2 (prec, m0, m1, NULL);
199   mpfr_from_real (m0, arg0, MPFR_RNDN);
200   mpfr_from_real (m1, arg1, MPFR_RNDN);
201   mpfr_clear_flags ();
202   bool inexact = func (m0, m0, m1, rnd);
203   bool ok = do_mpfr_ckconv (result, m0, inexact, format);
204   mpfr_clears (m0, m1, NULL);
205 
206   return ok;
207 }
208 
209 /* Try to evaluate:
210 
211       *RESULT = f (ARG0, *ARG1)
212 
213    in format FORMAT, given that FUNC is the MPFR implementation of f.
214    Return true on success.  */
215 
216 static bool
do_mpfr_arg2(real_value * result,int (* func)(mpfr_ptr,long,mpfr_srcptr,mpfr_rnd_t),const wide_int_ref & arg0,const real_value * arg1,const real_format * format)217 do_mpfr_arg2 (real_value *result,
218 	      int (*func) (mpfr_ptr, long, mpfr_srcptr, mpfr_rnd_t),
219 	      const wide_int_ref &arg0, const real_value *arg1,
220 	      const real_format *format)
221 {
222   if (format->b != 2 || !real_isfinite (arg1))
223     return false;
224 
225   int prec = format->p;
226   mpfr_rnd_t rnd = format->round_towards_zero ? MPFR_RNDZ : MPFR_RNDN;
227   mpfr_t m;
228 
229   mpfr_init2 (m, prec);
230   mpfr_from_real (m, arg1, MPFR_RNDN);
231   mpfr_clear_flags ();
232   bool inexact = func (m, arg0.to_shwi (), m, rnd);
233   bool ok = do_mpfr_ckconv (result, m, inexact, format);
234   mpfr_clear (m);
235 
236   return ok;
237 }
238 
239 /* Try to evaluate:
240 
241       *RESULT = f (*ARG0, *ARG1, *ARG2)
242 
243    in format FORMAT, given that FUNC is the MPFR implementation of f.
244    Return true on success.  */
245 
246 static bool
do_mpfr_arg3(real_value * result,int (* func)(mpfr_ptr,mpfr_srcptr,mpfr_srcptr,mpfr_srcptr,mpfr_rnd_t),const real_value * arg0,const real_value * arg1,const real_value * arg2,const real_format * format)247 do_mpfr_arg3 (real_value *result,
248 	      int (*func) (mpfr_ptr, mpfr_srcptr, mpfr_srcptr,
249 			   mpfr_srcptr, mpfr_rnd_t),
250 	      const real_value *arg0, const real_value *arg1,
251 	      const real_value *arg2, const real_format *format)
252 {
253   /* To proceed, MPFR must exactly represent the target floating point
254      format, which only happens when the target base equals two.  */
255   if (format->b != 2
256       || !real_isfinite (arg0)
257       || !real_isfinite (arg1)
258       || !real_isfinite (arg2))
259     return false;
260 
261   int prec = format->p;
262   mpfr_rnd_t rnd = format->round_towards_zero ? MPFR_RNDZ : MPFR_RNDN;
263   mpfr_t m0, m1, m2;
264 
265   mpfr_inits2 (prec, m0, m1, m2, NULL);
266   mpfr_from_real (m0, arg0, MPFR_RNDN);
267   mpfr_from_real (m1, arg1, MPFR_RNDN);
268   mpfr_from_real (m2, arg2, MPFR_RNDN);
269   mpfr_clear_flags ();
270   bool inexact = func (m0, m0, m1, m2, rnd);
271   bool ok = do_mpfr_ckconv (result, m0, inexact, format);
272   mpfr_clears (m0, m1, m2, NULL);
273 
274   return ok;
275 }
276 
277 /* M is the result of trying to constant-fold an expression (starting
278    with clear MPFR flags) and INEXACT says whether the result in M is
279    exact or inexact.  Return true if M can be used as a constant-folded
280    result in which the real and imaginary parts have format FORMAT.
281    Store those parts in *RESULT_REAL and *RESULT_IMAG if so.  */
282 
283 static bool
do_mpc_ckconv(real_value * result_real,real_value * result_imag,mpc_srcptr m,bool inexact,const real_format * format)284 do_mpc_ckconv (real_value *result_real, real_value *result_imag,
285 	       mpc_srcptr m, bool inexact, const real_format *format)
286 {
287   /* Proceed iff we get a normal number, i.e. not NaN or Inf and no
288      overflow/underflow occurred.  If -frounding-math, proceed iff the
289      result of calling FUNC was exact.  */
290   if (!mpfr_number_p (mpc_realref (m))
291       || !mpfr_number_p (mpc_imagref (m))
292       || mpfr_overflow_p ()
293       || mpfr_underflow_p ()
294       || (flag_rounding_math && inexact))
295     return false;
296 
297   REAL_VALUE_TYPE tmp_real, tmp_imag;
298   real_from_mpfr (&tmp_real, mpc_realref (m), format, MPFR_RNDN);
299   real_from_mpfr (&tmp_imag, mpc_imagref (m), format, MPFR_RNDN);
300 
301   /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR values.
302      If the REAL_VALUE_TYPE is zero but the mpft_t is not, then we
303      underflowed in the conversion.  */
304   if (!real_isfinite (&tmp_real)
305       || !real_isfinite (&tmp_imag)
306       || (tmp_real.cl == rvc_zero) != (mpfr_zero_p (mpc_realref (m)) != 0)
307       || (tmp_imag.cl == rvc_zero) != (mpfr_zero_p (mpc_imagref (m)) != 0))
308     return false;
309 
310   real_convert (result_real, format, &tmp_real);
311   real_convert (result_imag, format, &tmp_imag);
312 
313   return (real_identical (result_real, &tmp_real)
314 	  && real_identical (result_imag, &tmp_imag));
315 }
316 
317 /* Try to evaluate:
318 
319       RESULT = f (ARG)
320 
321    in format FORMAT, given that FUNC is the mpc implementation of f.
322    Return true on success.  Both RESULT and ARG are represented as
323    real and imaginary pairs.  */
324 
325 static bool
do_mpc_arg1(real_value * result_real,real_value * result_imag,int (* func)(mpc_ptr,mpc_srcptr,mpc_rnd_t),const real_value * arg_real,const real_value * arg_imag,const real_format * format)326 do_mpc_arg1 (real_value *result_real, real_value *result_imag,
327 	     int (*func) (mpc_ptr, mpc_srcptr, mpc_rnd_t),
328 	     const real_value *arg_real, const real_value *arg_imag,
329 	     const real_format *format)
330 {
331   /* To proceed, MPFR must exactly represent the target floating point
332      format, which only happens when the target base equals two.  */
333   if (format->b != 2
334       || !real_isfinite (arg_real)
335       || !real_isfinite (arg_imag))
336     return false;
337 
338   int prec = format->p;
339   mpc_rnd_t crnd = format->round_towards_zero ? MPC_RNDZZ : MPC_RNDNN;
340   mpc_t m;
341 
342   mpc_init2 (m, prec);
343   mpfr_from_real (mpc_realref (m), arg_real, MPFR_RNDN);
344   mpfr_from_real (mpc_imagref (m), arg_imag, MPFR_RNDN);
345   mpfr_clear_flags ();
346   bool inexact = func (m, m, crnd);
347   bool ok = do_mpc_ckconv (result_real, result_imag, m, inexact, format);
348   mpc_clear (m);
349 
350   return ok;
351 }
352 
353 /* Try to evaluate:
354 
355       RESULT = f (ARG0, ARG1)
356 
357    in format FORMAT, given that FUNC is the mpc implementation of f.
358    Return true on success.  RESULT, ARG0 and ARG1 are represented as
359    real and imaginary pairs.  */
360 
361 static bool
do_mpc_arg2(real_value * result_real,real_value * result_imag,int (* func)(mpc_ptr,mpc_srcptr,mpc_srcptr,mpc_rnd_t),const real_value * arg0_real,const real_value * arg0_imag,const real_value * arg1_real,const real_value * arg1_imag,const real_format * format)362 do_mpc_arg2 (real_value *result_real, real_value *result_imag,
363 	     int (*func)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t),
364 	     const real_value *arg0_real, const real_value *arg0_imag,
365 	     const real_value *arg1_real, const real_value *arg1_imag,
366 	     const real_format *format)
367 {
368   if (!real_isfinite (arg0_real)
369       || !real_isfinite (arg0_imag)
370       || !real_isfinite (arg1_real)
371       || !real_isfinite (arg1_imag))
372     return false;
373 
374   int prec = format->p;
375   mpc_rnd_t crnd = format->round_towards_zero ? MPC_RNDZZ : MPC_RNDNN;
376   mpc_t m0, m1;
377 
378   mpc_init2 (m0, prec);
379   mpc_init2 (m1, prec);
380   mpfr_from_real (mpc_realref (m0), arg0_real, MPFR_RNDN);
381   mpfr_from_real (mpc_imagref (m0), arg0_imag, MPFR_RNDN);
382   mpfr_from_real (mpc_realref (m1), arg1_real, MPFR_RNDN);
383   mpfr_from_real (mpc_imagref (m1), arg1_imag, MPFR_RNDN);
384   mpfr_clear_flags ();
385   bool inexact = func (m0, m0, m1, crnd);
386   bool ok = do_mpc_ckconv (result_real, result_imag, m0, inexact, format);
387   mpc_clear (m0);
388   mpc_clear (m1);
389 
390   return ok;
391 }
392 
393 /* Try to evaluate:
394 
395       *RESULT = logb (*ARG)
396 
397    in format FORMAT.  Return true on success.  */
398 
399 static bool
fold_const_logb(real_value * result,const real_value * arg,const real_format * format)400 fold_const_logb (real_value *result, const real_value *arg,
401 		 const real_format *format)
402 {
403   switch (arg->cl)
404     {
405     case rvc_nan:
406       /* If arg is +-NaN, then return it.  */
407       *result = *arg;
408       return true;
409 
410     case rvc_inf:
411       /* If arg is +-Inf, then return +Inf.  */
412       *result = *arg;
413       result->sign = 0;
414       return true;
415 
416     case rvc_zero:
417       /* Zero may set errno and/or raise an exception.  */
418       return false;
419 
420     case rvc_normal:
421       /* For normal numbers, proceed iff radix == 2.  In GCC,
422 	 normalized significands are in the range [0.5, 1.0).  We
423 	 want the exponent as if they were [1.0, 2.0) so get the
424 	 exponent and subtract 1.  */
425       if (format->b == 2)
426 	{
427 	  real_from_integer (result, format, REAL_EXP (arg) - 1, SIGNED);
428 	  return true;
429 	}
430       return false;
431     }
432 }
433 
434 /* Try to evaluate:
435 
436       *RESULT = significand (*ARG)
437 
438    in format FORMAT.  Return true on success.  */
439 
440 static bool
fold_const_significand(real_value * result,const real_value * arg,const real_format * format)441 fold_const_significand (real_value *result, const real_value *arg,
442 			const real_format *format)
443 {
444   switch (arg->cl)
445     {
446     case rvc_zero:
447     case rvc_nan:
448     case rvc_inf:
449       /* If arg is +-0, +-Inf or +-NaN, then return it.  */
450       *result = *arg;
451       return true;
452 
453     case rvc_normal:
454       /* For normal numbers, proceed iff radix == 2.  */
455       if (format->b == 2)
456 	{
457 	  *result = *arg;
458 	  /* In GCC, normalized significands are in the range [0.5, 1.0).
459 	     We want them to be [1.0, 2.0) so set the exponent to 1.  */
460 	  SET_REAL_EXP (result, 1);
461 	  return true;
462 	}
463       return false;
464     }
465 }
466 
467 /* Try to evaluate:
468 
469       *RESULT = f (*ARG)
470 
471    where FORMAT is the format of *ARG and PRECISION is the number of
472    significant bits in the result.  Return true on success.  */
473 
474 static bool
fold_const_conversion(wide_int * result,void (* fn)(real_value *,format_helper,const real_value *),const real_value * arg,unsigned int precision,const real_format * format)475 fold_const_conversion (wide_int *result,
476 		       void (*fn) (real_value *, format_helper,
477 				   const real_value *),
478 		       const real_value *arg, unsigned int precision,
479 		       const real_format *format)
480 {
481   if (!real_isfinite (arg))
482     return false;
483 
484   real_value rounded;
485   fn (&rounded, format, arg);
486 
487   bool fail = false;
488   *result = real_to_integer (&rounded, &fail, precision);
489   return !fail;
490 }
491 
492 /* Try to evaluate:
493 
494       *RESULT = pow (*ARG0, *ARG1)
495 
496    in format FORMAT.  Return true on success.  */
497 
498 static bool
fold_const_pow(real_value * result,const real_value * arg0,const real_value * arg1,const real_format * format)499 fold_const_pow (real_value *result, const real_value *arg0,
500 		const real_value *arg1, const real_format *format)
501 {
502   if (do_mpfr_arg2 (result, mpfr_pow, arg0, arg1, format))
503     return true;
504 
505   /* Check for an integer exponent.  */
506   REAL_VALUE_TYPE cint1;
507   HOST_WIDE_INT n1 = real_to_integer (arg1);
508   real_from_integer (&cint1, VOIDmode, n1, SIGNED);
509   /* Attempt to evaluate pow at compile-time, unless this should
510      raise an exception.  */
511   if (real_identical (arg1, &cint1)
512       && (n1 > 0
513 	  || (!flag_trapping_math && !flag_errno_math)
514 	  || !real_equal (arg0, &dconst0)))
515     {
516       bool inexact = real_powi (result, format, arg0, n1);
517       /* Avoid the folding if flag_signaling_nans is on.  */
518       if (flag_unsafe_math_optimizations
519 	  || (!inexact
520 	      && !(flag_signaling_nans
521 	           && REAL_VALUE_ISSIGNALING_NAN (*arg0))))
522 	return true;
523     }
524 
525   return false;
526 }
527 
528 /* Try to evaluate:
529 
530       *RESULT = nextafter (*ARG0, *ARG1)
531 
532    or
533 
534       *RESULT = nexttoward (*ARG0, *ARG1)
535 
536    in format FORMAT.  Return true on success.  */
537 
538 static bool
fold_const_nextafter(real_value * result,const real_value * arg0,const real_value * arg1,const real_format * format)539 fold_const_nextafter (real_value *result, const real_value *arg0,
540 		      const real_value *arg1, const real_format *format)
541 {
542   if (REAL_VALUE_ISSIGNALING_NAN (*arg0)
543       || REAL_VALUE_ISSIGNALING_NAN (*arg1))
544     return false;
545 
546   /* Don't handle composite modes, nor decimal, nor modes without
547      inf or denorm at least for now.  */
548   if (format->pnan < format->p
549       || format->b == 10
550       || !format->has_inf
551       || !format->has_denorm)
552     return false;
553 
554   if (real_nextafter (result, format, arg0, arg1)
555       /* If raising underflow or overflow and setting errno to ERANGE,
556 	 fail if we care about those side-effects.  */
557       && (flag_trapping_math || flag_errno_math))
558     return false;
559   /* Similarly for nextafter (0, 1) raising underflow.  */
560   else if (flag_trapping_math
561 	   && arg0->cl == rvc_zero
562 	   && result->cl != rvc_zero)
563     return false;
564 
565   real_convert (result, format, result);
566 
567   return true;
568 }
569 
570 /* Try to evaluate:
571 
572       *RESULT = ldexp (*ARG0, ARG1)
573 
574    in format FORMAT.  Return true on success.  */
575 
576 static bool
fold_const_builtin_load_exponent(real_value * result,const real_value * arg0,const wide_int_ref & arg1,const real_format * format)577 fold_const_builtin_load_exponent (real_value *result, const real_value *arg0,
578 				  const wide_int_ref &arg1,
579 				  const real_format *format)
580 {
581   /* Bound the maximum adjustment to twice the range of the
582      mode's valid exponents.  Use abs to ensure the range is
583      positive as a sanity check.  */
584   int max_exp_adj = 2 * labs (format->emax - format->emin);
585 
586   /* The requested adjustment must be inside this range.  This
587      is a preliminary cap to avoid things like overflow, we
588      may still fail to compute the result for other reasons.  */
589   if (wi::les_p (arg1, -max_exp_adj) || wi::ges_p (arg1, max_exp_adj))
590     return false;
591 
592   /* Don't perform operation if we honor signaling NaNs and
593      operand is a signaling NaN.  */
594   if (!flag_unsafe_math_optimizations
595       && flag_signaling_nans
596       && REAL_VALUE_ISSIGNALING_NAN (*arg0))
597     return false;
598 
599   REAL_VALUE_TYPE initial_result;
600   real_ldexp (&initial_result, arg0, arg1.to_shwi ());
601 
602   /* Ensure we didn't overflow.  */
603   if (real_isinf (&initial_result))
604     return false;
605 
606   /* Only proceed if the target mode can hold the
607      resulting value.  */
608   *result = real_value_truncate (format, initial_result);
609   return real_equal (&initial_result, result);
610 }
611 
612 /* Fold a call to __builtin_nan or __builtin_nans with argument ARG and
613    return type TYPE.  QUIET is true if a quiet rather than signalling
614    NaN is required.  */
615 
616 static tree
fold_const_builtin_nan(tree type,tree arg,bool quiet)617 fold_const_builtin_nan (tree type, tree arg, bool quiet)
618 {
619   REAL_VALUE_TYPE real;
620   const char *str = c_getstr (arg);
621   if (str && real_nan (&real, str, quiet, TYPE_MODE (type)))
622     return build_real (type, real);
623   return NULL_TREE;
624 }
625 
626 /* Fold a call to IFN_REDUC_<CODE> (ARG), returning a value of type TYPE.  */
627 
628 static tree
fold_const_reduction(tree type,tree arg,tree_code code)629 fold_const_reduction (tree type, tree arg, tree_code code)
630 {
631   unsigned HOST_WIDE_INT nelts;
632   if (TREE_CODE (arg) != VECTOR_CST
633       || !VECTOR_CST_NELTS (arg).is_constant (&nelts))
634     return NULL_TREE;
635 
636   tree res = VECTOR_CST_ELT (arg, 0);
637   for (unsigned HOST_WIDE_INT i = 1; i < nelts; i++)
638     {
639       res = const_binop (code, type, res, VECTOR_CST_ELT (arg, i));
640       if (res == NULL_TREE || !CONSTANT_CLASS_P (res))
641 	return NULL_TREE;
642     }
643   return res;
644 }
645 
646 /* Fold a call to IFN_VEC_CONVERT (ARG) returning TYPE.  */
647 
648 static tree
fold_const_vec_convert(tree ret_type,tree arg)649 fold_const_vec_convert (tree ret_type, tree arg)
650 {
651   enum tree_code code = NOP_EXPR;
652   tree arg_type = TREE_TYPE (arg);
653   if (TREE_CODE (arg) != VECTOR_CST)
654     return NULL_TREE;
655 
656   gcc_checking_assert (VECTOR_TYPE_P (ret_type) && VECTOR_TYPE_P (arg_type));
657 
658   if (INTEGRAL_TYPE_P (TREE_TYPE (ret_type))
659       && SCALAR_FLOAT_TYPE_P (TREE_TYPE (arg_type)))
660     code = FIX_TRUNC_EXPR;
661   else if (INTEGRAL_TYPE_P (TREE_TYPE (arg_type))
662 	   && SCALAR_FLOAT_TYPE_P (TREE_TYPE (ret_type)))
663     code = FLOAT_EXPR;
664 
665   /* We can't handle steps directly when extending, since the
666      values need to wrap at the original precision first.  */
667   bool step_ok_p
668     = (INTEGRAL_TYPE_P (TREE_TYPE (ret_type))
669        && INTEGRAL_TYPE_P (TREE_TYPE (arg_type))
670        && (TYPE_PRECISION (TREE_TYPE (ret_type))
671 	   <= TYPE_PRECISION (TREE_TYPE (arg_type))));
672   tree_vector_builder elts;
673   if (!elts.new_unary_operation (ret_type, arg, step_ok_p))
674     return NULL_TREE;
675 
676   unsigned int count = elts.encoded_nelts ();
677   for (unsigned int i = 0; i < count; ++i)
678     {
679       tree elt = fold_unary (code, TREE_TYPE (ret_type),
680 			     VECTOR_CST_ELT (arg, i));
681       if (elt == NULL_TREE || !CONSTANT_CLASS_P (elt))
682 	return NULL_TREE;
683       elts.quick_push (elt);
684     }
685 
686   return elts.build ();
687 }
688 
689 /* Try to evaluate:
690 
691       IFN_WHILE_ULT (ARG0, ARG1, (TYPE) { ... })
692 
693    Return the value on success and null on failure.  */
694 
695 static tree
fold_while_ult(tree type,poly_uint64 arg0,poly_uint64 arg1)696 fold_while_ult (tree type, poly_uint64 arg0, poly_uint64 arg1)
697 {
698   if (known_ge (arg0, arg1))
699     return build_zero_cst (type);
700 
701   if (maybe_ge (arg0, arg1))
702     return NULL_TREE;
703 
704   poly_uint64 diff = arg1 - arg0;
705   poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (type);
706   if (known_ge (diff, nelts))
707     return build_all_ones_cst (type);
708 
709   unsigned HOST_WIDE_INT const_diff;
710   if (known_le (diff, nelts) && diff.is_constant (&const_diff))
711     {
712       tree minus_one = build_minus_one_cst (TREE_TYPE (type));
713       tree zero = build_zero_cst (TREE_TYPE (type));
714       return build_vector_a_then_b (type, const_diff, minus_one, zero);
715     }
716   return NULL_TREE;
717 }
718 
719 /* Try to evaluate:
720 
721       *RESULT = FN (*ARG)
722 
723    in format FORMAT.  Return true on success.  */
724 
725 static bool
fold_const_call_ss(real_value * result,combined_fn fn,const real_value * arg,const real_format * format)726 fold_const_call_ss (real_value *result, combined_fn fn,
727 		    const real_value *arg, const real_format *format)
728 {
729   switch (fn)
730     {
731     CASE_CFN_SQRT:
732     CASE_CFN_SQRT_FN:
733       return (real_compare (GE_EXPR, arg, &dconst0)
734 	      && do_mpfr_arg1 (result, mpfr_sqrt, arg, format));
735 
736     CASE_CFN_CBRT:
737       return do_mpfr_arg1 (result, mpfr_cbrt, arg, format);
738 
739     CASE_CFN_ASIN:
740       return (real_compare (GE_EXPR, arg, &dconstm1)
741 	      && real_compare (LE_EXPR, arg, &dconst1)
742 	      && do_mpfr_arg1 (result, mpfr_asin, arg, format));
743 
744     CASE_CFN_ACOS:
745       return (real_compare (GE_EXPR, arg, &dconstm1)
746 	      && real_compare (LE_EXPR, arg, &dconst1)
747 	      && do_mpfr_arg1 (result, mpfr_acos, arg, format));
748 
749     CASE_CFN_ATAN:
750       return do_mpfr_arg1 (result, mpfr_atan, arg, format);
751 
752     CASE_CFN_ASINH:
753       return do_mpfr_arg1 (result, mpfr_asinh, arg, format);
754 
755     CASE_CFN_ACOSH:
756       return (real_compare (GE_EXPR, arg, &dconst1)
757 	      && do_mpfr_arg1 (result, mpfr_acosh, arg, format));
758 
759     CASE_CFN_ATANH:
760       return (real_compare (GE_EXPR, arg, &dconstm1)
761 	      && real_compare (LE_EXPR, arg, &dconst1)
762 	      && do_mpfr_arg1 (result, mpfr_atanh, arg, format));
763 
764     CASE_CFN_SIN:
765       return do_mpfr_arg1 (result, mpfr_sin, arg, format);
766 
767     CASE_CFN_COS:
768       return do_mpfr_arg1 (result, mpfr_cos, arg, format);
769 
770     CASE_CFN_TAN:
771       return do_mpfr_arg1 (result, mpfr_tan, arg, format);
772 
773     CASE_CFN_SINH:
774       return do_mpfr_arg1 (result, mpfr_sinh, arg, format);
775 
776     CASE_CFN_COSH:
777       return do_mpfr_arg1 (result, mpfr_cosh, arg, format);
778 
779     CASE_CFN_TANH:
780       return do_mpfr_arg1 (result, mpfr_tanh, arg, format);
781 
782     CASE_CFN_ERF:
783       return do_mpfr_arg1 (result, mpfr_erf, arg, format);
784 
785     CASE_CFN_ERFC:
786       return do_mpfr_arg1 (result, mpfr_erfc, arg, format);
787 
788     CASE_CFN_TGAMMA:
789       return do_mpfr_arg1 (result, mpfr_gamma, arg, format);
790 
791     CASE_CFN_EXP:
792       return do_mpfr_arg1 (result, mpfr_exp, arg, format);
793 
794     CASE_CFN_EXP2:
795       return do_mpfr_arg1 (result, mpfr_exp2, arg, format);
796 
797     CASE_CFN_EXP10:
798     CASE_CFN_POW10:
799       return do_mpfr_arg1 (result, mpfr_exp10, arg, format);
800 
801     CASE_CFN_EXPM1:
802       return do_mpfr_arg1 (result, mpfr_expm1, arg, format);
803 
804     CASE_CFN_LOG:
805       return (real_compare (GT_EXPR, arg, &dconst0)
806 	      && do_mpfr_arg1 (result, mpfr_log, arg, format));
807 
808     CASE_CFN_LOG2:
809       return (real_compare (GT_EXPR, arg, &dconst0)
810 	      && do_mpfr_arg1 (result, mpfr_log2, arg, format));
811 
812     CASE_CFN_LOG10:
813       return (real_compare (GT_EXPR, arg, &dconst0)
814 	      && do_mpfr_arg1 (result, mpfr_log10, arg, format));
815 
816     CASE_CFN_LOG1P:
817       return (real_compare (GT_EXPR, arg, &dconstm1)
818 	      && do_mpfr_arg1 (result, mpfr_log1p, arg, format));
819 
820     CASE_CFN_J0:
821       return do_mpfr_arg1 (result, mpfr_j0, arg, format);
822 
823     CASE_CFN_J1:
824       return do_mpfr_arg1 (result, mpfr_j1, arg, format);
825 
826     CASE_CFN_Y0:
827       return (real_compare (GT_EXPR, arg, &dconst0)
828 	      && do_mpfr_arg1 (result, mpfr_y0, arg, format));
829 
830     CASE_CFN_Y1:
831       return (real_compare (GT_EXPR, arg, &dconst0)
832 	      && do_mpfr_arg1 (result, mpfr_y1, arg, format));
833 
834     CASE_CFN_FLOOR:
835     CASE_CFN_FLOOR_FN:
836       if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
837 	{
838 	  real_floor (result, format, arg);
839 	  return true;
840 	}
841       return false;
842 
843     CASE_CFN_CEIL:
844     CASE_CFN_CEIL_FN:
845       if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
846 	{
847 	  real_ceil (result, format, arg);
848 	  return true;
849 	}
850       return false;
851 
852     CASE_CFN_TRUNC:
853     CASE_CFN_TRUNC_FN:
854       if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
855 	{
856 	  real_trunc (result, format, arg);
857 	  return true;
858 	}
859       return false;
860 
861     CASE_CFN_ROUND:
862     CASE_CFN_ROUND_FN:
863       if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
864 	{
865 	  real_round (result, format, arg);
866 	  return true;
867 	}
868       return false;
869 
870     CASE_CFN_ROUNDEVEN:
871     CASE_CFN_ROUNDEVEN_FN:
872       if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
873 	{
874 	  real_roundeven (result, format, arg);
875 	  return true;
876 	}
877       return false;
878 
879     CASE_CFN_LOGB:
880       return fold_const_logb (result, arg, format);
881 
882     CASE_CFN_SIGNIFICAND:
883       return fold_const_significand (result, arg, format);
884 
885     default:
886       return false;
887     }
888 }
889 
890 /* Try to evaluate:
891 
892       *RESULT = FN (*ARG)
893 
894    where FORMAT is the format of ARG and PRECISION is the number of
895    significant bits in the result.  Return true on success.  */
896 
897 static bool
fold_const_call_ss(wide_int * result,combined_fn fn,const real_value * arg,unsigned int precision,const real_format * format)898 fold_const_call_ss (wide_int *result, combined_fn fn,
899 		    const real_value *arg, unsigned int precision,
900 		    const real_format *format)
901 {
902   switch (fn)
903     {
904     CASE_CFN_SIGNBIT:
905       if (real_isneg (arg))
906 	*result = wi::one (precision);
907       else
908 	*result = wi::zero (precision);
909       return true;
910 
911     CASE_CFN_ILOGB:
912       /* For ilogb we don't know FP_ILOGB0, so only handle normal values.
913 	 Proceed iff radix == 2.  In GCC, normalized significands are in
914 	 the range [0.5, 1.0).  We want the exponent as if they were
915 	 [1.0, 2.0) so get the exponent and subtract 1.  */
916       if (arg->cl == rvc_normal && format->b == 2)
917 	{
918 	  *result = wi::shwi (REAL_EXP (arg) - 1, precision);
919 	  return true;
920 	}
921       return false;
922 
923     CASE_CFN_ICEIL:
924     CASE_CFN_LCEIL:
925     CASE_CFN_LLCEIL:
926       return fold_const_conversion (result, real_ceil, arg,
927 				    precision, format);
928 
929     CASE_CFN_LFLOOR:
930     CASE_CFN_IFLOOR:
931     CASE_CFN_LLFLOOR:
932       return fold_const_conversion (result, real_floor, arg,
933 				    precision, format);
934 
935     CASE_CFN_IROUND:
936     CASE_CFN_LROUND:
937     CASE_CFN_LLROUND:
938       return fold_const_conversion (result, real_round, arg,
939 				    precision, format);
940 
941     CASE_CFN_IRINT:
942     CASE_CFN_LRINT:
943     CASE_CFN_LLRINT:
944       /* Not yet folded to a constant.  */
945       return false;
946 
947     CASE_CFN_FINITE:
948     case CFN_BUILT_IN_FINITED32:
949     case CFN_BUILT_IN_FINITED64:
950     case CFN_BUILT_IN_FINITED128:
951     case CFN_BUILT_IN_ISFINITE:
952       *result = wi::shwi (real_isfinite (arg) ? 1 : 0, precision);
953       return true;
954 
955     CASE_CFN_ISINF:
956     case CFN_BUILT_IN_ISINFD32:
957     case CFN_BUILT_IN_ISINFD64:
958     case CFN_BUILT_IN_ISINFD128:
959       if (real_isinf (arg))
960 	*result = wi::shwi (arg->sign ? -1 : 1, precision);
961       else
962 	*result = wi::shwi (0, precision);
963       return true;
964 
965     CASE_CFN_ISNAN:
966     case CFN_BUILT_IN_ISNAND32:
967     case CFN_BUILT_IN_ISNAND64:
968     case CFN_BUILT_IN_ISNAND128:
969       *result = wi::shwi (real_isnan (arg) ? 1 : 0, precision);
970       return true;
971 
972     default:
973       return false;
974     }
975 }
976 
977 /* Try to evaluate:
978 
979       *RESULT = FN (ARG)
980 
981    where ARG_TYPE is the type of ARG and PRECISION is the number of bits
982    in the result.  Return true on success.  */
983 
984 static bool
fold_const_call_ss(wide_int * result,combined_fn fn,const wide_int_ref & arg,unsigned int precision,tree arg_type)985 fold_const_call_ss (wide_int *result, combined_fn fn, const wide_int_ref &arg,
986 		    unsigned int precision, tree arg_type)
987 {
988   switch (fn)
989     {
990     CASE_CFN_FFS:
991       *result = wi::shwi (wi::ffs (arg), precision);
992       return true;
993 
994     CASE_CFN_CLZ:
995       {
996 	int tmp;
997 	if (wi::ne_p (arg, 0))
998 	  tmp = wi::clz (arg);
999 	else if (!CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (arg_type),
1000 					     tmp))
1001 	  tmp = TYPE_PRECISION (arg_type);
1002 	*result = wi::shwi (tmp, precision);
1003 	return true;
1004       }
1005 
1006     CASE_CFN_CTZ:
1007       {
1008 	int tmp;
1009 	if (wi::ne_p (arg, 0))
1010 	  tmp = wi::ctz (arg);
1011 	else if (!CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (arg_type),
1012 					     tmp))
1013 	  tmp = TYPE_PRECISION (arg_type);
1014 	*result = wi::shwi (tmp, precision);
1015 	return true;
1016       }
1017 
1018     CASE_CFN_CLRSB:
1019       *result = wi::shwi (wi::clrsb (arg), precision);
1020       return true;
1021 
1022     CASE_CFN_POPCOUNT:
1023       *result = wi::shwi (wi::popcount (arg), precision);
1024       return true;
1025 
1026     CASE_CFN_PARITY:
1027       *result = wi::shwi (wi::parity (arg), precision);
1028       return true;
1029 
1030     case CFN_BUILT_IN_BSWAP16:
1031     case CFN_BUILT_IN_BSWAP32:
1032     case CFN_BUILT_IN_BSWAP64:
1033     case CFN_BUILT_IN_BSWAP128:
1034       *result = wide_int::from (arg, precision, TYPE_SIGN (arg_type)).bswap ();
1035       return true;
1036 
1037     default:
1038       return false;
1039     }
1040 }
1041 
1042 /* Try to evaluate:
1043 
1044       RESULT = FN (*ARG)
1045 
1046    where FORMAT is the format of ARG and of the real and imaginary parts
1047    of RESULT, passed as RESULT_REAL and RESULT_IMAG respectively.  Return
1048    true on success.  */
1049 
1050 static bool
fold_const_call_cs(real_value * result_real,real_value * result_imag,combined_fn fn,const real_value * arg,const real_format * format)1051 fold_const_call_cs (real_value *result_real, real_value *result_imag,
1052 		    combined_fn fn, const real_value *arg,
1053 		    const real_format *format)
1054 {
1055   switch (fn)
1056     {
1057     CASE_CFN_CEXPI:
1058       /* cexpi(x+yi) = cos(x)+sin(y)*i.  */
1059       return do_mpfr_sincos (result_imag, result_real, arg, format);
1060 
1061     default:
1062       return false;
1063     }
1064 }
1065 
1066 /* Try to evaluate:
1067 
1068       *RESULT = fn (ARG)
1069 
1070    where FORMAT is the format of RESULT and of the real and imaginary parts
1071    of ARG, passed as ARG_REAL and ARG_IMAG respectively.  Return true on
1072    success.  */
1073 
1074 static bool
fold_const_call_sc(real_value * result,combined_fn fn,const real_value * arg_real,const real_value * arg_imag,const real_format * format)1075 fold_const_call_sc (real_value *result, combined_fn fn,
1076 		    const real_value *arg_real, const real_value *arg_imag,
1077 		    const real_format *format)
1078 {
1079   switch (fn)
1080     {
1081     CASE_CFN_CABS:
1082       return do_mpfr_arg2 (result, mpfr_hypot, arg_real, arg_imag, format);
1083 
1084     default:
1085       return false;
1086     }
1087 }
1088 
1089 /* Try to evaluate:
1090 
1091       RESULT = fn (ARG)
1092 
1093    where FORMAT is the format of the real and imaginary parts of RESULT
1094    (RESULT_REAL and RESULT_IMAG) and of ARG (ARG_REAL and ARG_IMAG).
1095    Return true on success.  */
1096 
1097 static bool
fold_const_call_cc(real_value * result_real,real_value * result_imag,combined_fn fn,const real_value * arg_real,const real_value * arg_imag,const real_format * format)1098 fold_const_call_cc (real_value *result_real, real_value *result_imag,
1099 		    combined_fn fn, const real_value *arg_real,
1100 		    const real_value *arg_imag, const real_format *format)
1101 {
1102   switch (fn)
1103     {
1104     CASE_CFN_CCOS:
1105       return do_mpc_arg1 (result_real, result_imag, mpc_cos,
1106 			  arg_real, arg_imag, format);
1107 
1108     CASE_CFN_CCOSH:
1109       return do_mpc_arg1 (result_real, result_imag, mpc_cosh,
1110 			  arg_real, arg_imag, format);
1111 
1112     CASE_CFN_CPROJ:
1113       if (real_isinf (arg_real) || real_isinf (arg_imag))
1114 	{
1115 	  real_inf (result_real);
1116 	  *result_imag = dconst0;
1117 	  result_imag->sign = arg_imag->sign;
1118 	}
1119       else
1120 	{
1121 	  *result_real = *arg_real;
1122 	  *result_imag = *arg_imag;
1123 	}
1124       return true;
1125 
1126     CASE_CFN_CSIN:
1127       return do_mpc_arg1 (result_real, result_imag, mpc_sin,
1128 			  arg_real, arg_imag, format);
1129 
1130     CASE_CFN_CSINH:
1131       return do_mpc_arg1 (result_real, result_imag, mpc_sinh,
1132 			  arg_real, arg_imag, format);
1133 
1134     CASE_CFN_CTAN:
1135       return do_mpc_arg1 (result_real, result_imag, mpc_tan,
1136 			  arg_real, arg_imag, format);
1137 
1138     CASE_CFN_CTANH:
1139       return do_mpc_arg1 (result_real, result_imag, mpc_tanh,
1140 			  arg_real, arg_imag, format);
1141 
1142     CASE_CFN_CLOG:
1143       return do_mpc_arg1 (result_real, result_imag, mpc_log,
1144 			  arg_real, arg_imag, format);
1145 
1146     CASE_CFN_CSQRT:
1147       return do_mpc_arg1 (result_real, result_imag, mpc_sqrt,
1148 			  arg_real, arg_imag, format);
1149 
1150     CASE_CFN_CASIN:
1151       return do_mpc_arg1 (result_real, result_imag, mpc_asin,
1152 			  arg_real, arg_imag, format);
1153 
1154     CASE_CFN_CACOS:
1155       return do_mpc_arg1 (result_real, result_imag, mpc_acos,
1156 			  arg_real, arg_imag, format);
1157 
1158     CASE_CFN_CATAN:
1159       return do_mpc_arg1 (result_real, result_imag, mpc_atan,
1160 			  arg_real, arg_imag, format);
1161 
1162     CASE_CFN_CASINH:
1163       return do_mpc_arg1 (result_real, result_imag, mpc_asinh,
1164 			  arg_real, arg_imag, format);
1165 
1166     CASE_CFN_CACOSH:
1167       return do_mpc_arg1 (result_real, result_imag, mpc_acosh,
1168 			  arg_real, arg_imag, format);
1169 
1170     CASE_CFN_CATANH:
1171       return do_mpc_arg1 (result_real, result_imag, mpc_atanh,
1172 			  arg_real, arg_imag, format);
1173 
1174     CASE_CFN_CEXP:
1175       return do_mpc_arg1 (result_real, result_imag, mpc_exp,
1176 			  arg_real, arg_imag, format);
1177 
1178     default:
1179       return false;
1180     }
1181 }
1182 
1183 /* Subroutine of fold_const_call, with the same interface.  Handle cases
1184    where the arguments and result are numerical.  */
1185 
1186 static tree
fold_const_call_1(combined_fn fn,tree type,tree arg)1187 fold_const_call_1 (combined_fn fn, tree type, tree arg)
1188 {
1189   machine_mode mode = TYPE_MODE (type);
1190   machine_mode arg_mode = TYPE_MODE (TREE_TYPE (arg));
1191 
1192   if (integer_cst_p (arg))
1193     {
1194       if (SCALAR_INT_MODE_P (mode))
1195 	{
1196 	  wide_int result;
1197 	  if (fold_const_call_ss (&result, fn, wi::to_wide (arg),
1198 				  TYPE_PRECISION (type), TREE_TYPE (arg)))
1199 	    return wide_int_to_tree (type, result);
1200 	}
1201       return NULL_TREE;
1202     }
1203 
1204   if (real_cst_p (arg))
1205     {
1206       gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg_mode));
1207       if (mode == arg_mode)
1208 	{
1209 	  /* real -> real.  */
1210 	  REAL_VALUE_TYPE result;
1211 	  if (fold_const_call_ss (&result, fn, TREE_REAL_CST_PTR (arg),
1212 				  REAL_MODE_FORMAT (mode)))
1213 	    return build_real (type, result);
1214 	}
1215       else if (COMPLEX_MODE_P (mode)
1216 	       && GET_MODE_INNER (mode) == arg_mode)
1217 	{
1218 	  /* real -> complex real.  */
1219 	  REAL_VALUE_TYPE result_real, result_imag;
1220 	  if (fold_const_call_cs (&result_real, &result_imag, fn,
1221 				  TREE_REAL_CST_PTR (arg),
1222 				  REAL_MODE_FORMAT (arg_mode)))
1223 	    return build_complex (type,
1224 				  build_real (TREE_TYPE (type), result_real),
1225 				  build_real (TREE_TYPE (type), result_imag));
1226 	}
1227       else if (INTEGRAL_TYPE_P (type))
1228 	{
1229 	  /* real -> int.  */
1230 	  wide_int result;
1231 	  if (fold_const_call_ss (&result, fn,
1232 				  TREE_REAL_CST_PTR (arg),
1233 				  TYPE_PRECISION (type),
1234 				  REAL_MODE_FORMAT (arg_mode)))
1235 	    return wide_int_to_tree (type, result);
1236 	}
1237       return NULL_TREE;
1238     }
1239 
1240   if (complex_cst_p (arg))
1241     {
1242       gcc_checking_assert (COMPLEX_MODE_P (arg_mode));
1243       machine_mode inner_mode = GET_MODE_INNER (arg_mode);
1244       tree argr = TREE_REALPART (arg);
1245       tree argi = TREE_IMAGPART (arg);
1246       if (mode == arg_mode
1247 	  && real_cst_p (argr)
1248 	  && real_cst_p (argi))
1249 	{
1250 	  /* complex real -> complex real.  */
1251 	  REAL_VALUE_TYPE result_real, result_imag;
1252 	  if (fold_const_call_cc (&result_real, &result_imag, fn,
1253 				  TREE_REAL_CST_PTR (argr),
1254 				  TREE_REAL_CST_PTR (argi),
1255 				  REAL_MODE_FORMAT (inner_mode)))
1256 	    return build_complex (type,
1257 				  build_real (TREE_TYPE (type), result_real),
1258 				  build_real (TREE_TYPE (type), result_imag));
1259 	}
1260       if (mode == inner_mode
1261 	  && real_cst_p (argr)
1262 	  && real_cst_p (argi))
1263 	{
1264 	  /* complex real -> real.  */
1265 	  REAL_VALUE_TYPE result;
1266 	  if (fold_const_call_sc (&result, fn,
1267 				  TREE_REAL_CST_PTR (argr),
1268 				  TREE_REAL_CST_PTR (argi),
1269 				  REAL_MODE_FORMAT (inner_mode)))
1270 	    return build_real (type, result);
1271 	}
1272       return NULL_TREE;
1273     }
1274 
1275   return NULL_TREE;
1276 }
1277 
1278 /* Try to fold FN (ARG) to a constant.  Return the constant on success,
1279    otherwise return null.  TYPE is the type of the return value.  */
1280 
1281 tree
fold_const_call(combined_fn fn,tree type,tree arg)1282 fold_const_call (combined_fn fn, tree type, tree arg)
1283 {
1284   switch (fn)
1285     {
1286     case CFN_BUILT_IN_STRLEN:
1287       if (const char *str = c_getstr (arg))
1288 	return build_int_cst (type, strlen (str));
1289       return NULL_TREE;
1290 
1291     CASE_CFN_NAN:
1292     CASE_FLT_FN_FLOATN_NX (CFN_BUILT_IN_NAN):
1293     case CFN_BUILT_IN_NAND32:
1294     case CFN_BUILT_IN_NAND64:
1295     case CFN_BUILT_IN_NAND128:
1296       return fold_const_builtin_nan (type, arg, true);
1297 
1298     CASE_CFN_NANS:
1299     CASE_FLT_FN_FLOATN_NX (CFN_BUILT_IN_NANS):
1300     case CFN_BUILT_IN_NANSD32:
1301     case CFN_BUILT_IN_NANSD64:
1302     case CFN_BUILT_IN_NANSD128:
1303       return fold_const_builtin_nan (type, arg, false);
1304 
1305     case CFN_REDUC_PLUS:
1306       return fold_const_reduction (type, arg, PLUS_EXPR);
1307 
1308     case CFN_REDUC_MAX:
1309       return fold_const_reduction (type, arg, MAX_EXPR);
1310 
1311     case CFN_REDUC_MIN:
1312       return fold_const_reduction (type, arg, MIN_EXPR);
1313 
1314     case CFN_REDUC_AND:
1315       return fold_const_reduction (type, arg, BIT_AND_EXPR);
1316 
1317     case CFN_REDUC_IOR:
1318       return fold_const_reduction (type, arg, BIT_IOR_EXPR);
1319 
1320     case CFN_REDUC_XOR:
1321       return fold_const_reduction (type, arg, BIT_XOR_EXPR);
1322 
1323     case CFN_VEC_CONVERT:
1324       return fold_const_vec_convert (type, arg);
1325 
1326     default:
1327       return fold_const_call_1 (fn, type, arg);
1328     }
1329 }
1330 
1331 /* Fold a call to IFN_FOLD_LEFT_<CODE> (ARG0, ARG1), returning a value
1332    of type TYPE.  */
1333 
1334 static tree
fold_const_fold_left(tree type,tree arg0,tree arg1,tree_code code)1335 fold_const_fold_left (tree type, tree arg0, tree arg1, tree_code code)
1336 {
1337   if (TREE_CODE (arg1) != VECTOR_CST)
1338     return NULL_TREE;
1339 
1340   unsigned HOST_WIDE_INT nelts;
1341   if (!VECTOR_CST_NELTS (arg1).is_constant (&nelts))
1342     return NULL_TREE;
1343 
1344   for (unsigned HOST_WIDE_INT i = 0; i < nelts; i++)
1345     {
1346       arg0 = const_binop (code, type, arg0, VECTOR_CST_ELT (arg1, i));
1347       if (arg0 == NULL_TREE || !CONSTANT_CLASS_P (arg0))
1348 	return NULL_TREE;
1349     }
1350   return arg0;
1351 }
1352 
1353 /* Try to evaluate:
1354 
1355       *RESULT = FN (*ARG0, *ARG1)
1356 
1357    in format FORMAT.  Return true on success.  */
1358 
1359 static bool
fold_const_call_sss(real_value * result,combined_fn fn,const real_value * arg0,const real_value * arg1,const real_format * format)1360 fold_const_call_sss (real_value *result, combined_fn fn,
1361 		     const real_value *arg0, const real_value *arg1,
1362 		     const real_format *format)
1363 {
1364   switch (fn)
1365     {
1366     CASE_CFN_DREM:
1367     CASE_CFN_REMAINDER:
1368       return do_mpfr_arg2 (result, mpfr_remainder, arg0, arg1, format);
1369 
1370     CASE_CFN_ATAN2:
1371       return do_mpfr_arg2 (result, mpfr_atan2, arg0, arg1, format);
1372 
1373     CASE_CFN_FDIM:
1374       return do_mpfr_arg2 (result, mpfr_dim, arg0, arg1, format);
1375 
1376     CASE_CFN_FMOD:
1377       return do_mpfr_arg2 (result, mpfr_fmod, arg0, arg1, format);
1378 
1379     CASE_CFN_HYPOT:
1380       return do_mpfr_arg2 (result, mpfr_hypot, arg0, arg1, format);
1381 
1382     CASE_CFN_COPYSIGN:
1383     CASE_CFN_COPYSIGN_FN:
1384       *result = *arg0;
1385       real_copysign (result, arg1);
1386       return true;
1387 
1388     CASE_CFN_FMIN:
1389     CASE_CFN_FMIN_FN:
1390       return do_mpfr_arg2 (result, mpfr_min, arg0, arg1, format);
1391 
1392     CASE_CFN_FMAX:
1393     CASE_CFN_FMAX_FN:
1394       return do_mpfr_arg2 (result, mpfr_max, arg0, arg1, format);
1395 
1396     CASE_CFN_POW:
1397       return fold_const_pow (result, arg0, arg1, format);
1398 
1399     CASE_CFN_NEXTAFTER:
1400     CASE_CFN_NEXTTOWARD:
1401       return fold_const_nextafter (result, arg0, arg1, format);
1402 
1403     default:
1404       return false;
1405     }
1406 }
1407 
1408 /* Try to evaluate:
1409 
1410       *RESULT = FN (*ARG0, ARG1)
1411 
1412    where FORMAT is the format of *RESULT and *ARG0.  Return true on
1413    success.  */
1414 
1415 static bool
fold_const_call_sss(real_value * result,combined_fn fn,const real_value * arg0,const wide_int_ref & arg1,const real_format * format)1416 fold_const_call_sss (real_value *result, combined_fn fn,
1417 		     const real_value *arg0, const wide_int_ref &arg1,
1418 		     const real_format *format)
1419 {
1420   switch (fn)
1421     {
1422     CASE_CFN_LDEXP:
1423       return fold_const_builtin_load_exponent (result, arg0, arg1, format);
1424 
1425     CASE_CFN_SCALBN:
1426     CASE_CFN_SCALBLN:
1427       return (format->b == 2
1428 	      && fold_const_builtin_load_exponent (result, arg0, arg1,
1429 						   format));
1430 
1431     CASE_CFN_POWI:
1432       /* Avoid the folding if flag_signaling_nans is on and
1433          operand is a signaling NaN.  */
1434       if (!flag_unsafe_math_optimizations
1435 	  && flag_signaling_nans
1436 	  && REAL_VALUE_ISSIGNALING_NAN (*arg0))
1437         return false;
1438 
1439       real_powi (result, format, arg0, arg1.to_shwi ());
1440       return true;
1441 
1442     default:
1443       return false;
1444     }
1445 }
1446 
1447 /* Try to evaluate:
1448 
1449       *RESULT = FN (ARG0, *ARG1)
1450 
1451    where FORMAT is the format of *RESULT and *ARG1.  Return true on
1452    success.  */
1453 
1454 static bool
fold_const_call_sss(real_value * result,combined_fn fn,const wide_int_ref & arg0,const real_value * arg1,const real_format * format)1455 fold_const_call_sss (real_value *result, combined_fn fn,
1456 		     const wide_int_ref &arg0, const real_value *arg1,
1457 		     const real_format *format)
1458 {
1459   switch (fn)
1460     {
1461     CASE_CFN_JN:
1462       return do_mpfr_arg2 (result, mpfr_jn, arg0, arg1, format);
1463 
1464     CASE_CFN_YN:
1465       return (real_compare (GT_EXPR, arg1, &dconst0)
1466 	      && do_mpfr_arg2 (result, mpfr_yn, arg0, arg1, format));
1467 
1468     default:
1469       return false;
1470     }
1471 }
1472 
1473 /* Try to evaluate:
1474 
1475       RESULT = fn (ARG0, ARG1)
1476 
1477    where FORMAT is the format of the real and imaginary parts of RESULT
1478    (RESULT_REAL and RESULT_IMAG), of ARG0 (ARG0_REAL and ARG0_IMAG)
1479    and of ARG1 (ARG1_REAL and ARG1_IMAG).  Return true on success.  */
1480 
1481 static bool
fold_const_call_ccc(real_value * result_real,real_value * result_imag,combined_fn fn,const real_value * arg0_real,const real_value * arg0_imag,const real_value * arg1_real,const real_value * arg1_imag,const real_format * format)1482 fold_const_call_ccc (real_value *result_real, real_value *result_imag,
1483 		     combined_fn fn, const real_value *arg0_real,
1484 		     const real_value *arg0_imag, const real_value *arg1_real,
1485 		     const real_value *arg1_imag, const real_format *format)
1486 {
1487   switch (fn)
1488     {
1489     CASE_CFN_CPOW:
1490       return do_mpc_arg2 (result_real, result_imag, mpc_pow,
1491 			  arg0_real, arg0_imag, arg1_real, arg1_imag, format);
1492 
1493     default:
1494       return false;
1495     }
1496 }
1497 
1498 /* Subroutine of fold_const_call, with the same interface.  Handle cases
1499    where the arguments and result are numerical.  */
1500 
1501 static tree
fold_const_call_1(combined_fn fn,tree type,tree arg0,tree arg1)1502 fold_const_call_1 (combined_fn fn, tree type, tree arg0, tree arg1)
1503 {
1504   machine_mode mode = TYPE_MODE (type);
1505   machine_mode arg0_mode = TYPE_MODE (TREE_TYPE (arg0));
1506   machine_mode arg1_mode = TYPE_MODE (TREE_TYPE (arg1));
1507 
1508   if (mode == arg0_mode
1509       && real_cst_p (arg0)
1510       && real_cst_p (arg1))
1511     {
1512       gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg0_mode));
1513       REAL_VALUE_TYPE result;
1514       if (arg0_mode == arg1_mode)
1515 	{
1516 	  /* real, real -> real.  */
1517 	  if (fold_const_call_sss (&result, fn, TREE_REAL_CST_PTR (arg0),
1518 				   TREE_REAL_CST_PTR (arg1),
1519 				   REAL_MODE_FORMAT (mode)))
1520 	    return build_real (type, result);
1521 	}
1522       else if (arg1_mode == TYPE_MODE (long_double_type_node))
1523 	switch (fn)
1524 	  {
1525 	  CASE_CFN_NEXTTOWARD:
1526 	    /* real, long double -> real.  */
1527 	    if (fold_const_call_sss (&result, fn, TREE_REAL_CST_PTR (arg0),
1528 				     TREE_REAL_CST_PTR (arg1),
1529 				     REAL_MODE_FORMAT (mode)))
1530 	      return build_real (type, result);
1531 	    break;
1532 	  default:
1533 	    break;
1534 	  }
1535       return NULL_TREE;
1536     }
1537 
1538   if (real_cst_p (arg0)
1539       && integer_cst_p (arg1))
1540     {
1541       gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg0_mode));
1542       if (mode == arg0_mode)
1543 	{
1544 	  /* real, int -> real.  */
1545 	  REAL_VALUE_TYPE result;
1546 	  if (fold_const_call_sss (&result, fn, TREE_REAL_CST_PTR (arg0),
1547 				   wi::to_wide (arg1),
1548 				   REAL_MODE_FORMAT (mode)))
1549 	    return build_real (type, result);
1550 	}
1551       return NULL_TREE;
1552     }
1553 
1554   if (integer_cst_p (arg0)
1555       && real_cst_p (arg1))
1556     {
1557       gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg1_mode));
1558       if (mode == arg1_mode)
1559 	{
1560 	  /* int, real -> real.  */
1561 	  REAL_VALUE_TYPE result;
1562 	  if (fold_const_call_sss (&result, fn, wi::to_wide (arg0),
1563 				   TREE_REAL_CST_PTR (arg1),
1564 				   REAL_MODE_FORMAT (mode)))
1565 	    return build_real (type, result);
1566 	}
1567       return NULL_TREE;
1568     }
1569 
1570   if (arg0_mode == arg1_mode
1571       && complex_cst_p (arg0)
1572       && complex_cst_p (arg1))
1573     {
1574       gcc_checking_assert (COMPLEX_MODE_P (arg0_mode));
1575       machine_mode inner_mode = GET_MODE_INNER (arg0_mode);
1576       tree arg0r = TREE_REALPART (arg0);
1577       tree arg0i = TREE_IMAGPART (arg0);
1578       tree arg1r = TREE_REALPART (arg1);
1579       tree arg1i = TREE_IMAGPART (arg1);
1580       if (mode == arg0_mode
1581 	  && real_cst_p (arg0r)
1582 	  && real_cst_p (arg0i)
1583 	  && real_cst_p (arg1r)
1584 	  && real_cst_p (arg1i))
1585 	{
1586 	  /* complex real, complex real -> complex real.  */
1587 	  REAL_VALUE_TYPE result_real, result_imag;
1588 	  if (fold_const_call_ccc (&result_real, &result_imag, fn,
1589 				   TREE_REAL_CST_PTR (arg0r),
1590 				   TREE_REAL_CST_PTR (arg0i),
1591 				   TREE_REAL_CST_PTR (arg1r),
1592 				   TREE_REAL_CST_PTR (arg1i),
1593 				   REAL_MODE_FORMAT (inner_mode)))
1594 	    return build_complex (type,
1595 				  build_real (TREE_TYPE (type), result_real),
1596 				  build_real (TREE_TYPE (type), result_imag));
1597 	}
1598       return NULL_TREE;
1599     }
1600 
1601   return NULL_TREE;
1602 }
1603 
1604 /* Try to fold FN (ARG0, ARG1) to a constant.  Return the constant on success,
1605    otherwise return null.  TYPE is the type of the return value.  */
1606 
1607 tree
fold_const_call(combined_fn fn,tree type,tree arg0,tree arg1)1608 fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1)
1609 {
1610   const char *p0, *p1;
1611   char c;
1612   switch (fn)
1613     {
1614     case CFN_BUILT_IN_STRSPN:
1615       if ((p0 = c_getstr (arg0)) && (p1 = c_getstr (arg1)))
1616 	return build_int_cst (type, strspn (p0, p1));
1617       return NULL_TREE;
1618 
1619     case CFN_BUILT_IN_STRCSPN:
1620       if ((p0 = c_getstr (arg0)) && (p1 = c_getstr (arg1)))
1621 	return build_int_cst (type, strcspn (p0, p1));
1622       return NULL_TREE;
1623 
1624     case CFN_BUILT_IN_STRCMP:
1625       if ((p0 = c_getstr (arg0)) && (p1 = c_getstr (arg1)))
1626 	return build_cmp_result (type, strcmp (p0, p1));
1627       return NULL_TREE;
1628 
1629     case CFN_BUILT_IN_STRCASECMP:
1630       if ((p0 = c_getstr (arg0)) && (p1 = c_getstr (arg1)))
1631 	{
1632 	  int r = strcmp (p0, p1);
1633 	  if (r == 0)
1634 	    return build_cmp_result (type, r);
1635 	}
1636       return NULL_TREE;
1637 
1638     case CFN_BUILT_IN_INDEX:
1639     case CFN_BUILT_IN_STRCHR:
1640       if ((p0 = c_getstr (arg0)) && target_char_cst_p (arg1, &c))
1641 	{
1642 	  const char *r = strchr (p0, c);
1643 	  if (r == NULL)
1644 	    return build_int_cst (type, 0);
1645 	  return fold_convert (type,
1646 			       fold_build_pointer_plus_hwi (arg0, r - p0));
1647 	}
1648       return NULL_TREE;
1649 
1650     case CFN_BUILT_IN_RINDEX:
1651     case CFN_BUILT_IN_STRRCHR:
1652       if ((p0 = c_getstr (arg0)) && target_char_cst_p (arg1, &c))
1653 	{
1654 	  const char *r = strrchr (p0, c);
1655 	  if (r == NULL)
1656 	    return build_int_cst (type, 0);
1657 	  return fold_convert (type,
1658 			       fold_build_pointer_plus_hwi (arg0, r - p0));
1659 	}
1660       return NULL_TREE;
1661 
1662     case CFN_BUILT_IN_STRSTR:
1663       if ((p1 = c_getstr (arg1)))
1664 	{
1665 	  if ((p0 = c_getstr (arg0)))
1666 	    {
1667 	      const char *r = strstr (p0, p1);
1668 	      if (r == NULL)
1669 		return build_int_cst (type, 0);
1670 	      return fold_convert (type,
1671 				   fold_build_pointer_plus_hwi (arg0, r - p0));
1672 	    }
1673 	  if (*p1 == '\0')
1674 	    return fold_convert (type, arg0);
1675 	}
1676       return NULL_TREE;
1677 
1678     case CFN_FOLD_LEFT_PLUS:
1679       return fold_const_fold_left (type, arg0, arg1, PLUS_EXPR);
1680 
1681     default:
1682       return fold_const_call_1 (fn, type, arg0, arg1);
1683     }
1684 }
1685 
1686 /* Try to evaluate:
1687 
1688       *RESULT = FN (*ARG0, *ARG1, *ARG2)
1689 
1690    in format FORMAT.  Return true on success.  */
1691 
1692 static bool
fold_const_call_ssss(real_value * result,combined_fn fn,const real_value * arg0,const real_value * arg1,const real_value * arg2,const real_format * format)1693 fold_const_call_ssss (real_value *result, combined_fn fn,
1694 		      const real_value *arg0, const real_value *arg1,
1695 		      const real_value *arg2, const real_format *format)
1696 {
1697   switch (fn)
1698     {
1699     CASE_CFN_FMA:
1700     CASE_CFN_FMA_FN:
1701       return do_mpfr_arg3 (result, mpfr_fma, arg0, arg1, arg2, format);
1702 
1703     case CFN_FMS:
1704       {
1705 	real_value new_arg2 = real_value_negate (arg2);
1706 	return do_mpfr_arg3 (result, mpfr_fma, arg0, arg1, &new_arg2, format);
1707       }
1708 
1709     case CFN_FNMA:
1710       {
1711 	real_value new_arg0 = real_value_negate (arg0);
1712 	return do_mpfr_arg3 (result, mpfr_fma, &new_arg0, arg1, arg2, format);
1713       }
1714 
1715     case CFN_FNMS:
1716       {
1717 	real_value new_arg0 = real_value_negate (arg0);
1718 	real_value new_arg2 = real_value_negate (arg2);
1719 	return do_mpfr_arg3 (result, mpfr_fma, &new_arg0, arg1,
1720 			     &new_arg2, format);
1721       }
1722 
1723     default:
1724       return false;
1725     }
1726 }
1727 
1728 /* Subroutine of fold_const_call, with the same interface.  Handle cases
1729    where the arguments and result are numerical.  */
1730 
1731 static tree
fold_const_call_1(combined_fn fn,tree type,tree arg0,tree arg1,tree arg2)1732 fold_const_call_1 (combined_fn fn, tree type, tree arg0, tree arg1, tree arg2)
1733 {
1734   machine_mode mode = TYPE_MODE (type);
1735   machine_mode arg0_mode = TYPE_MODE (TREE_TYPE (arg0));
1736   machine_mode arg1_mode = TYPE_MODE (TREE_TYPE (arg1));
1737   machine_mode arg2_mode = TYPE_MODE (TREE_TYPE (arg2));
1738 
1739   if (arg0_mode == arg1_mode
1740       && arg0_mode == arg2_mode
1741       && real_cst_p (arg0)
1742       && real_cst_p (arg1)
1743       && real_cst_p (arg2))
1744     {
1745       gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg0_mode));
1746       if (mode == arg0_mode)
1747 	{
1748 	  /* real, real, real -> real.  */
1749 	  REAL_VALUE_TYPE result;
1750 	  if (fold_const_call_ssss (&result, fn, TREE_REAL_CST_PTR (arg0),
1751 				    TREE_REAL_CST_PTR (arg1),
1752 				    TREE_REAL_CST_PTR (arg2),
1753 				    REAL_MODE_FORMAT (mode)))
1754 	    return build_real (type, result);
1755 	}
1756       return NULL_TREE;
1757     }
1758 
1759   return NULL_TREE;
1760 }
1761 
1762 /* Try to fold FN (ARG0, ARG1, ARG2) to a constant.  Return the constant on
1763    success, otherwise return null.  TYPE is the type of the return value.  */
1764 
1765 tree
fold_const_call(combined_fn fn,tree type,tree arg0,tree arg1,tree arg2)1766 fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1, tree arg2)
1767 {
1768   const char *p0, *p1;
1769   char c;
1770   unsigned HOST_WIDE_INT s0, s1, s2 = 0;
1771   switch (fn)
1772     {
1773     case CFN_BUILT_IN_STRNCMP:
1774       if (!size_t_cst_p (arg2, &s2))
1775 	return NULL_TREE;
1776       if (s2 == 0
1777 	  && !TREE_SIDE_EFFECTS (arg0)
1778 	  && !TREE_SIDE_EFFECTS (arg1))
1779 	return build_int_cst (type, 0);
1780       else if ((p0 = c_getstr (arg0)) && (p1 = c_getstr (arg1)))
1781 	return build_int_cst (type, strncmp (p0, p1, MIN (s2, SIZE_MAX)));
1782       return NULL_TREE;
1783 
1784     case CFN_BUILT_IN_STRNCASECMP:
1785       if (!size_t_cst_p (arg2, &s2))
1786 	return NULL_TREE;
1787       if (s2 == 0
1788 	  && !TREE_SIDE_EFFECTS (arg0)
1789 	  && !TREE_SIDE_EFFECTS (arg1))
1790 	return build_int_cst (type, 0);
1791       else if ((p0 = c_getstr (arg0))
1792 	       && (p1 = c_getstr (arg1))
1793 	       && strncmp (p0, p1, MIN (s2, SIZE_MAX)) == 0)
1794 	return build_int_cst (type, 0);
1795       return NULL_TREE;
1796 
1797     case CFN_BUILT_IN_BCMP:
1798     case CFN_BUILT_IN_MEMCMP:
1799       if (!size_t_cst_p (arg2, &s2))
1800 	return NULL_TREE;
1801       if (s2 == 0
1802 	  && !TREE_SIDE_EFFECTS (arg0)
1803 	  && !TREE_SIDE_EFFECTS (arg1))
1804 	return build_int_cst (type, 0);
1805       if ((p0 = getbyterep (arg0, &s0))
1806 	  && (p1 = getbyterep (arg1, &s1))
1807 	  && s2 <= s0
1808 	  && s2 <= s1)
1809 	return build_cmp_result (type, memcmp (p0, p1, s2));
1810       return NULL_TREE;
1811 
1812     case CFN_BUILT_IN_MEMCHR:
1813       if (!size_t_cst_p (arg2, &s2))
1814 	return NULL_TREE;
1815       if (s2 == 0
1816 	  && !TREE_SIDE_EFFECTS (arg0)
1817 	  && !TREE_SIDE_EFFECTS (arg1))
1818 	return build_int_cst (type, 0);
1819       if ((p0 = getbyterep (arg0, &s0))
1820 	  && s2 <= s0
1821 	  && target_char_cst_p (arg1, &c))
1822 	{
1823 	  const char *r = (const char *) memchr (p0, c, s2);
1824 	  if (r == NULL)
1825 	    return build_int_cst (type, 0);
1826 	  return fold_convert (type,
1827 			       fold_build_pointer_plus_hwi (arg0, r - p0));
1828 	}
1829       return NULL_TREE;
1830 
1831     case CFN_WHILE_ULT:
1832       {
1833 	poly_uint64 parg0, parg1;
1834 	if (poly_int_tree_p (arg0, &parg0) && poly_int_tree_p (arg1, &parg1))
1835 	  return fold_while_ult (type, parg0, parg1);
1836 	return NULL_TREE;
1837       }
1838 
1839     default:
1840       return fold_const_call_1 (fn, type, arg0, arg1, arg2);
1841     }
1842 }
1843