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// long double __gcc_qmul(long double x, long double y);
6353358Sdim// This file implements the PowerPC 128-bit double-double multiply operation.
7353358Sdim// This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
8276789Sdim
9276789Sdim#include "DD.h"
10276789Sdim
11353358Sdimlong double __gcc_qmul(long double x, long double y) {
12353358Sdim  static const uint32_t infinityHi = UINT32_C(0x7ff00000);
13353358Sdim  DD dst = {.ld = x}, src = {.ld = y};
14353358Sdim
15353358Sdim  register double A = dst.s.hi, a = dst.s.lo, B = src.s.hi, b = src.s.lo;
16353358Sdim
17353358Sdim  double aHi, aLo, bHi, bLo;
18353358Sdim  double ab, tmp, tau;
19353358Sdim
20353358Sdim  ab = A * B;
21353358Sdim
22353358Sdim  // Detect special cases
23353358Sdim  if (ab == 0.0) {
24353358Sdim    dst.s.hi = ab;
25353358Sdim    dst.s.lo = 0.0;
26276789Sdim    return dst.ld;
27353358Sdim  }
28353358Sdim
29353358Sdim  const doublebits abBits = {.d = ab};
30353358Sdim  if (((uint32_t)(abBits.x >> 32) & infinityHi) == infinityHi) {
31353358Sdim    dst.s.hi = ab;
32353358Sdim    dst.s.lo = 0.0;
33353358Sdim    return dst.ld;
34353358Sdim  }
35353358Sdim
36353358Sdim  // Generic cases handled here.
37353358Sdim  aHi = high26bits(A);
38353358Sdim  bHi = high26bits(B);
39353358Sdim  aLo = A - aHi;
40353358Sdim  bLo = B - bHi;
41353358Sdim
42353358Sdim  tmp = LOWORDER(ab, aHi, aLo, bHi, bLo);
43353358Sdim  tmp += (A * b + a * B);
44353358Sdim  tau = ab + tmp;
45353358Sdim
46353358Sdim  dst.s.lo = (ab - tau) + tmp;
47353358Sdim  dst.s.hi = tau;
48353358Sdim
49353358Sdim  return dst.ld;
50276789Sdim}
51