Skip to content

Commit

Permalink
[libc] Add nearest integer instructions to fputil.
Browse files Browse the repository at this point in the history
Add round to nearest integer instructions to fputil.  This will be
used in sinf implementation https://reviews.llvm.org/D123154

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D129776
  • Loading branch information
lntue committed Jul 14, 2022
1 parent ecfaf48 commit 0f782b8
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 0 deletions.
8 changes: 8 additions & 0 deletions libc/src/__support/FPUtil/CMakeLists.txt
Expand Up @@ -69,4 +69,12 @@ add_header_library(
.multiply_add
)

add_header_library(
nearest_integer
HDRS
nearest_integer.h
DEPENDS
libc.src.__support.common
)

add_subdirectory(generic)
30 changes: 30 additions & 0 deletions libc/src/__support/FPUtil/aarch64/nearest_integer.h
@@ -0,0 +1,30 @@
//===--- Round floating point to nearest integer on aarch64 -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_AARCH64_NEAREST_INTEGER_H
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_AARCH64_NEAREST_INTEGER_H

#include "src/__support/architectures.h"

#if !defined(LLVM_LIBC_ARCH_AARCH64)
#error "Invalid include"
#endif

namespace __llvm_libc {
namespace fputil {

static inline double nearest_integer(double x) {
double result;
__asm__ __volatile__("frintn %d0, %d1\n\t" : "=w"(result) : "w"(x));
return result;
}

} // namespace fputil
} // namespace __llvm_libc

#endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_AARCH64_NEAREST_INTEGER_H
51 changes: 51 additions & 0 deletions libc/src/__support/FPUtil/nearest_integer.h
@@ -0,0 +1,51 @@
//===-- Fast rounding to nearest integer for floating point -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_H
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_H

#include "src/__support/architectures.h"
#include "src/__support/common.h"

#if (defined(LLVM_LIBC_ARCH_X86_64) && defined(__SSE4_2__))
#include "x86_64/nearest_integer.h"
#elif defined(LLVM_LIBC_ARCH_AARCH64)
#include "aarch64/nearest_integer.h"
#else

namespace __llvm_libc {
namespace fputil {

// This is a fast implementation for rounding to a nearest integer that, in case
// of a tie, might pick a random one among 2 closest integers when the rounding
// mode is not FE_TONEAREST.
//
// Notice that for AARCH64 and x86-64 with SSE4.2 support, we will use their
// corresponding rounding instruction instead. And in those cases, the results
// are rounded to the nearest integer, tie-to-even.
static inline double nearest_integer(double x) {
if (x < 0x1p53 && x > -0x1p53) {
double r = x < 0 ? (x - 0x1.0p52) + 0x1.0p52 : (x + 0x1.0p52) - 0x1.0p52;
double diff = x - r;
// The expression above is correct for the default rounding mode, round-to-
// nearest, tie-to-even. For other rounding modes, it might be off by 1,
// which is corrected below.
if (unlikely(diff > 0.5))
return r + 1.0;
if (unlikely(diff < -0.5))
return r - 1.0;
return r;
}
return x;
}

} // namespace fputil
} // namespace __llvm_libc

#endif
#endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_H
37 changes: 37 additions & 0 deletions libc/src/__support/FPUtil/x86_64/nearest_integer.h
@@ -0,0 +1,37 @@
//===--- Round floating point to nearest integer on x86-64 ------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_NEAREST_INTEGER_H
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_NEAREST_INTEGER_H

#include "src/__support/architectures.h"

#if !defined(LLVM_LIBC_ARCH_X86_64)
#error "Invalid include"
#endif

#if !defined(__SSE4_2__)
#error "SSE4.2 instruction set is not supported"
#endif

#include <immintrin.h>

namespace __llvm_libc {
namespace fputil {

static inline double nearest_integer(double x) {
__m128d xmm = _mm_set_sd(x); // NOLINT
__m128d ymm =
_mm_round_sd(xmm, xmm, _MM_ROUND_NEAREST | _MM_FROUND_NO_EXC); // NOLINT
return ymm[0];
}

} // namespace fputil
} // namespace __llvm_libc

#endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_NEAREST_INTEGER_H
22 changes: 22 additions & 0 deletions utils/bazel/llvm-project-overlay/libc/BUILD.bazel
Expand Up @@ -263,6 +263,28 @@ cc_library(
],
)

nearest_integer_common_hdrs = [
"src/__support/FPUtil/nearest_integer.h",
]

nearest_integer_platform_hdrs = [
"src/__support/FPUtil/x86_64/nearest_integer.h",
"src/__support/FPUtil/aarch64/nearest_integer.h",
]

cc_library(
name = "__support_fputil_nearest_integer",
hdrs = nearest_integer_common_hdrs,
# These are conditionally included and will #error out if the platform
# doesn't support rounding instructions, so they can't be compiled on their
# own.
textual_hdrs = nearest_integer_platform_hdrs,
deps = [
":__support_common",
":libc_root",
],
)

################################ fenv targets ################################

libc_function(
Expand Down

0 comments on commit 0f782b8

Please sign in to comment.