+#ifdef HAVE_mpc
+/* If argument ARG is a COMPLEX_CST, call the one-argument mpc
+ function FUNC on it and return the resulting value as a tree with
+ type TYPE. The mpfr precision is set to the precision of TYPE. We
+ assume that function FUNC returns zero if the result could be
+ calculated exactly within the requested precision. */
+
+static tree
+do_mpc_arg1 (tree arg, tree type, int (*func)(mpc_ptr, mpc_srcptr, mpc_rnd_t))
+{
+ tree result = NULL_TREE;
+
+ STRIP_NOPS (arg);
+
+ /* To proceed, MPFR must exactly represent the target floating point
+ format, which only happens when the target base equals two. */
+ if (TREE_CODE (arg) == COMPLEX_CST && !TREE_OVERFLOW (arg)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE
+ && REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (TREE_TYPE (arg))))->b == 2)
+ {
+ const REAL_VALUE_TYPE *const re = TREE_REAL_CST_PTR (TREE_REALPART (arg));
+ const REAL_VALUE_TYPE *const im = TREE_REAL_CST_PTR (TREE_IMAGPART (arg));
+
+ if (real_isfinite (re) && real_isfinite (im))
+ {
+ const struct real_format *const fmt =
+ REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (type)));
+ const int prec = fmt->p;
+ const mp_rnd_t rnd = fmt->round_towards_zero ? GMP_RNDZ : GMP_RNDN;
+ const mpc_rnd_t crnd = fmt->round_towards_zero ? MPC_RNDZZ : MPC_RNDNN;
+ int inexact;
+ mpc_t m;
+
+ mpc_init2 (m, prec);
+ mpfr_from_real (mpc_realref(m), re, rnd);
+ mpfr_from_real (mpc_imagref(m), im, rnd);
+ mpfr_clear_flags ();
+ inexact = func (m, m, crnd);
+ result = do_mpc_ckconv (m, type, inexact, /*force_convert=*/ 0);
+ mpc_clear (m);
+ }
+ }
+
+ return result;
+}
+
+/* If arguments ARG0 and ARG1 are a COMPLEX_CST, call the two-argument
+ mpc function FUNC on it and return the resulting value as a tree
+ with type TYPE. The mpfr precision is set to the precision of
+ TYPE. We assume that function FUNC returns zero if the result
+ could be calculated exactly within the requested precision. If
+ DO_NONFINITE is true, then fold expressions containing Inf or NaN
+ in the arguments and/or results. */
+
+#ifdef HAVE_mpc
+tree
+do_mpc_arg2 (tree arg0, tree arg1, tree type, int do_nonfinite,
+ int (*func)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t))
+{
+ tree result = NULL_TREE;
+
+ STRIP_NOPS (arg0);
+ STRIP_NOPS (arg1);
+
+ /* To proceed, MPFR must exactly represent the target floating point
+ format, which only happens when the target base equals two. */
+ if (TREE_CODE (arg0) == COMPLEX_CST && !TREE_OVERFLOW (arg0)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE
+ && TREE_CODE (arg1) == COMPLEX_CST && !TREE_OVERFLOW (arg1)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg1))) == REAL_TYPE
+ && REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0))))->b == 2)
+ {
+ const REAL_VALUE_TYPE *const re0 = TREE_REAL_CST_PTR (TREE_REALPART (arg0));
+ const REAL_VALUE_TYPE *const im0 = TREE_REAL_CST_PTR (TREE_IMAGPART (arg0));
+ const REAL_VALUE_TYPE *const re1 = TREE_REAL_CST_PTR (TREE_REALPART (arg1));
+ const REAL_VALUE_TYPE *const im1 = TREE_REAL_CST_PTR (TREE_IMAGPART (arg1));
+
+ if (do_nonfinite
+ || (real_isfinite (re0) && real_isfinite (im0)
+ && real_isfinite (re1) && real_isfinite (im1)))
+ {
+ const struct real_format *const fmt =
+ REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (type)));
+ const int prec = fmt->p;
+ const mp_rnd_t rnd = fmt->round_towards_zero ? GMP_RNDZ : GMP_RNDN;
+ const mpc_rnd_t crnd = fmt->round_towards_zero ? MPC_RNDZZ : MPC_RNDNN;
+ int inexact;
+ mpc_t m0, m1;
+
+ mpc_init2 (m0, prec);
+ mpc_init2 (m1, prec);
+ mpfr_from_real (mpc_realref(m0), re0, rnd);
+ mpfr_from_real (mpc_imagref(m0), im0, rnd);
+ mpfr_from_real (mpc_realref(m1), re1, rnd);
+ mpfr_from_real (mpc_imagref(m1), im1, rnd);
+ mpfr_clear_flags ();
+ inexact = func (m0, m0, m1, crnd);
+ result = do_mpc_ckconv (m0, type, inexact, do_nonfinite);
+ mpc_clear (m0);
+ mpc_clear (m1);
+ }
+ }
+
+ return result;
+}
+# endif
+#endif /* HAVE_mpc */
+