[libc] Add nearest integer instructions to fputil.

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
This commit is contained in:
Tue Ly 2022-07-14 10:43:32 -04:00
parent ecfaf4801c
commit 0f782b84cb
5 changed files with 148 additions and 0 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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(