1//===-- floatundisf.c - Implement __floatundisf ---------------------------===//
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 __floatundisf for the compiler_rt library.
10//
11//===----------------------------------------------------------------------===//
12
13// Returns: convert a to a float, rounding toward even.
14
15// Assumption: float is a IEEE 32 bit floating point type
16//            du_int is a 64 bit integral type
17
18// seee eeee emmm mmmm mmmm mmmm mmmm mmmm
19
20#include "int_lib.h"
21
22COMPILER_RT_ABI float __floatundisf(du_int a) {
23  if (a == 0)
24    return 0.0F;
25  const unsigned N = sizeof(du_int) * CHAR_BIT;
26  int sd = N - __builtin_clzll(a); // number of significant digits
27  si_int e = sd - 1;               // 8 exponent
28  if (sd > FLT_MANT_DIG) {
29    //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
30    //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
31    //                                                12345678901234567890123456
32    //  1 = msb 1 bit
33    //  P = bit FLT_MANT_DIG-1 bits to the right of 1
34    //  Q = bit FLT_MANT_DIG bits to the right of 1
35    //  R = "or" of all bits to the right of Q
36    switch (sd) {
37    case FLT_MANT_DIG + 1:
38      a <<= 1;
39      break;
40    case FLT_MANT_DIG + 2:
41      break;
42    default:
43      a = (a >> (sd - (FLT_MANT_DIG + 2))) |
44          ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0);
45    };
46    // finish:
47    a |= (a & 4) != 0; // Or P into R
48    ++a;               // round - this step may add a significant bit
49    a >>= 2;           // dump Q and R
50    // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
51    if (a & ((du_int)1 << FLT_MANT_DIG)) {
52      a >>= 1;
53      ++e;
54    }
55    // a is now rounded to FLT_MANT_DIG bits
56  } else {
57    a <<= (FLT_MANT_DIG - sd);
58    // a is now rounded to FLT_MANT_DIG bits
59  }
60  float_bits fb;
61  fb.u = ((e + 127) << 23) |       // exponent
62         ((su_int)a & 0x007FFFFF); // mantissa
63  return fb.f;
64}
65
66#if defined(__ARM_EABI__)
67#if defined(COMPILER_RT_ARMHF_TARGET)
68AEABI_RTABI float __aeabi_ul2f(du_int a) { return __floatundisf(a); }
69#else
70COMPILER_RT_ALIAS(__floatundisf, __aeabi_ul2f)
71#endif
72#endif
73