1353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2353358Sdim// See https://llvm.org/LICENSE.txt for license information.
3353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4276789Sdim
5353358Sdim#include "../int_math.h"
6276789Sdim#include "DD.h"
7276789Sdim
8353358Sdim#define makeFinite(x)                                                          \
9353358Sdim  {                                                                            \
10353358Sdim    (x).s.hi = crt_copysign(crt_isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi);        \
11353358Sdim    (x).s.lo = 0.0;                                                            \
12276789Sdim  }
13276789Sdim
14353358Sdim#define zeroNaN(x)                                                             \
15353358Sdim  {                                                                            \
16353358Sdim    if (crt_isnan((x).s.hi)) {                                                 \
17353358Sdim      (x).s.hi = crt_copysign(0.0, (x).s.hi);                                  \
18353358Sdim      (x).s.lo = 0.0;                                                          \
19353358Sdim    }                                                                          \
20276789Sdim  }
21276789Sdim
22353358Sdimlong double _Complex __multc3(long double a, long double b, long double c,
23353358Sdim                              long double d) {
24353358Sdim  long double ac = __gcc_qmul(a, c);
25353358Sdim  long double bd = __gcc_qmul(b, d);
26353358Sdim  long double ad = __gcc_qmul(a, d);
27353358Sdim  long double bc = __gcc_qmul(b, c);
28353358Sdim
29353358Sdim  DD real = {.ld = __gcc_qsub(ac, bd)};
30353358Sdim  DD imag = {.ld = __gcc_qadd(ad, bc)};
31353358Sdim
32353358Sdim  if (crt_isnan(real.s.hi) && crt_isnan(imag.s.hi)) {
33353358Sdim    int recalc = 0;
34353358Sdim
35353358Sdim    DD aDD = {.ld = a};
36353358Sdim    DD bDD = {.ld = b};
37353358Sdim    DD cDD = {.ld = c};
38353358Sdim    DD dDD = {.ld = d};
39353358Sdim
40353358Sdim    if (crt_isinf(aDD.s.hi) || crt_isinf(bDD.s.hi)) {
41353358Sdim      makeFinite(aDD);
42353358Sdim      makeFinite(bDD);
43353358Sdim      zeroNaN(cDD);
44353358Sdim      zeroNaN(dDD);
45353358Sdim      recalc = 1;
46353358Sdim    }
47353358Sdim
48353358Sdim    if (crt_isinf(cDD.s.hi) || crt_isinf(dDD.s.hi)) {
49353358Sdim      makeFinite(cDD);
50353358Sdim      makeFinite(dDD);
51353358Sdim      zeroNaN(aDD);
52353358Sdim      zeroNaN(bDD);
53353358Sdim      recalc = 1;
54353358Sdim    }
55353358Sdim
56353358Sdim    if (!recalc) {
57353358Sdim      DD acDD = {.ld = ac};
58353358Sdim      DD bdDD = {.ld = bd};
59353358Sdim      DD adDD = {.ld = ad};
60353358Sdim      DD bcDD = {.ld = bc};
61353358Sdim
62353358Sdim      if (crt_isinf(acDD.s.hi) || crt_isinf(bdDD.s.hi) ||
63353358Sdim          crt_isinf(adDD.s.hi) || crt_isinf(bcDD.s.hi)) {
64353358Sdim        zeroNaN(aDD);
65353358Sdim        zeroNaN(bDD);
66353358Sdim        zeroNaN(cDD);
67353358Sdim        zeroNaN(dDD);
68353358Sdim        recalc = 1;
69353358Sdim      }
70353358Sdim    }
71353358Sdim
72353358Sdim    if (recalc) {
73353358Sdim      real.s.hi = CRT_INFINITY * (aDD.s.hi * cDD.s.hi - bDD.s.hi * dDD.s.hi);
74353358Sdim      real.s.lo = 0.0;
75353358Sdim      imag.s.hi = CRT_INFINITY * (aDD.s.hi * dDD.s.hi + bDD.s.hi * cDD.s.hi);
76353358Sdim      imag.s.lo = 0.0;
77353358Sdim    }
78353358Sdim  }
79353358Sdim
80353358Sdim  long double _Complex z;
81353358Sdim  __real__ z = real.ld;
82353358Sdim  __imag__ z = imag.ld;
83353358Sdim
84353358Sdim  return z;
85276789Sdim}
86