1//===-- floattisf.c - Implement __floattisf -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements __floattisf for the compiler_rt library.
10//
11//===----------------------------------------------------------------------===//
12
13#include "int_lib.h"
14
15#ifdef CRT_HAS_128BIT
16
17// Returns: convert a to a float, rounding toward even.
18
19// Assumption: float is a IEEE 32 bit floating point type
20//             ti_int is a 128 bit integral type
21
22// seee eeee emmm mmmm mmmm mmmm mmmm mmmm
23
24COMPILER_RT_ABI float __floattisf(ti_int a) {
25  if (a == 0)
26    return 0.0F;
27  const unsigned N = sizeof(ti_int) * CHAR_BIT;
28  const ti_int s = a >> (N - 1);
29  a = (a ^ s) - s;
30  int sd = N - __clzti2(a); // number of significant digits
31  int e = sd - 1;           // exponent
32  if (sd > FLT_MANT_DIG) {
33    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
34    // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
35    //                                                12345678901234567890123456
36    //  1 = msb 1 bit
37    //  P = bit FLT_MANT_DIG-1 bits to the right of 1
38    //  Q = bit FLT_MANT_DIG bits to the right of 1
39    //  R = "or" of all bits to the right of Q
40    switch (sd) {
41    case FLT_MANT_DIG + 1:
42      a <<= 1;
43      break;
44    case FLT_MANT_DIG + 2:
45      break;
46    default:
47      a = ((tu_int)a >> (sd - (FLT_MANT_DIG + 2))) |
48          ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0);
49    };
50    // finish:
51    a |= (a & 4) != 0; // Or P into R
52    ++a;               // round - this step may add a significant bit
53    a >>= 2;           // dump Q and R
54    // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
55    if (a & ((tu_int)1 << FLT_MANT_DIG)) {
56      a >>= 1;
57      ++e;
58    }
59    // a is now rounded to FLT_MANT_DIG bits
60  } else {
61    a <<= (FLT_MANT_DIG - sd);
62    // a is now rounded to FLT_MANT_DIG bits
63  }
64  float_bits fb;
65  fb.u = ((su_int)s & 0x80000000) | // sign
66         ((e + 127) << 23) |        // exponent
67         ((su_int)a & 0x007FFFFF);  // mantissa
68  return fb.f;
69}
70
71#endif // CRT_HAS_128BIT
72