From 2dd05b302ecefead0c849efdadbe3a48b2492b94 Mon Sep 17 00:00:00 2001 From: Yi Kong Date: Thu, 5 Sep 2019 01:05:05 +0000 Subject: Revert "Revert "[builtins] Rounding mode support for addxf3/subxf3"" Test failure fixed. This reverts commit e204d244badb2e9765a1020f41c773f63da208f4. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@371003 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 3 ++ lib/builtins/aarch64/fp_mode.c | 59 ++++++++++++++++++++++++++++++++++++++++ lib/builtins/adddf3.c | 3 +- lib/builtins/addsf3.c | 3 +- lib/builtins/addtf3.c | 3 +- lib/builtins/arm/fp_mode.c | 59 ++++++++++++++++++++++++++++++++++++++++ lib/builtins/fp_add_impl.inc | 23 +++++++++++++--- lib/builtins/fp_mode.c | 24 ++++++++++++++++ lib/builtins/fp_mode.h | 29 ++++++++++++++++++++ lib/builtins/subdf3.c | 3 +- lib/builtins/subsf3.c | 3 +- lib/builtins/subtf3.c | 3 +- test/builtins/Unit/addtf3_test.c | 33 +++++++++++++++++++++- test/builtins/Unit/subtf3_test.c | 30 ++++++++++++++++++++ 14 files changed, 261 insertions(+), 17 deletions(-) create mode 100644 lib/builtins/aarch64/fp_mode.c create mode 100644 lib/builtins/arm/fp_mode.c create mode 100644 lib/builtins/fp_mode.c create mode 100644 lib/builtins/fp_mode.h diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 4062efcb3..f42e13714 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -97,6 +97,7 @@ set(GENERIC_SOURCES floatunsisf.c floatuntidf.c floatuntisf.c + fp_mode.c int_util.c lshrdi3.c lshrti3.c @@ -306,6 +307,7 @@ set(i386_SOURCES ${i386_SOURCES} ${x86_ARCH_SOURCES}) set(i686_SOURCES ${i686_SOURCES} ${x86_ARCH_SOURCES}) set(arm_SOURCES + arm/fp_mode.c arm/bswapdi2.S arm/bswapsi2.S arm/clzdi2.S @@ -451,6 +453,7 @@ endif() set(aarch64_SOURCES ${GENERIC_TF_SOURCES} ${GENERIC_SOURCES} + aarch64/fp_mode.c ) if (MINGW) diff --git a/lib/builtins/aarch64/fp_mode.c b/lib/builtins/aarch64/fp_mode.c new file mode 100644 index 000000000..5a413689d --- /dev/null +++ b/lib/builtins/aarch64/fp_mode.c @@ -0,0 +1,59 @@ +//===----- lib/aarch64/fp_mode.c - Floaing-point mode utilities ---*- 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 +// +//===----------------------------------------------------------------------===// + +#include + +#include "../fp_mode.h" + +#define AARCH64_TONEAREST 0x0 +#define AARCH64_UPWARD 0x1 +#define AARCH64_DOWNWARD 0x2 +#define AARCH64_TOWARDZERO 0x3 +#define AARCH64_RMODE_MASK (AARCH64_TONEAREST | AARCH64_UPWARD | \ + AARCH64_DOWNWARD | AARCH64_TOWARDZERO) +#define AARCH64_RMODE_SHIFT 22 + +#define AARCH64_INEXACT 0x10 + +#ifndef __ARM_FP +// For soft float targets, allow changing rounding mode by overriding the weak +// __aarch64_fe_default_rmode symbol. +FE_ROUND_MODE __attribute__((weak)) __aarch64_fe_default_rmode = FE_TONEAREST; +#endif + +FE_ROUND_MODE __fe_getround() { +#ifdef __ARM_FP + uint64_t fpcr; + __asm__ __volatile__("mrs %0, fpcr" : "=r" (fpcr)); + fpcr = fpcr >> AARCH64_RMODE_SHIFT & AARCH64_RMODE_MASK; + switch (fpcr) { + case AARCH64_UPWARD: + return FE_UPWARD; + case AARCH64_DOWNWARD: + return FE_DOWNWARD; + case AARCH64_TOWARDZERO: + return FE_TOWARDZERO; + case AARCH64_TONEAREST: + default: + return FE_TONEAREST; + } +#else + return __aarch64_fe_default_rmode; +#endif +} + +int __fe_raise_inexact() { +#ifdef __ARM_FP + uint64_t fpsr; + __asm__ __volatile__("mrs %0, fpsr" : "=r" (fpsr)); + __asm__ __volatile__("msr fpsr, %0" : : "ri" (fpsr | AARCH64_INEXACT)); + return 0; +#else + return 0; +#endif +} diff --git a/lib/builtins/adddf3.c b/lib/builtins/adddf3.c index f2727fafc..26f11bfa2 100644 --- a/lib/builtins/adddf3.c +++ b/lib/builtins/adddf3.c @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements double-precision soft-float addition with the IEEE-754 -// default rounding (to nearest, ties to even). +// This file implements double-precision soft-float addition. // //===----------------------------------------------------------------------===// diff --git a/lib/builtins/addsf3.c b/lib/builtins/addsf3.c index 8fe8622aa..9f1d517c1 100644 --- a/lib/builtins/addsf3.c +++ b/lib/builtins/addsf3.c @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements single-precision soft-float addition with the IEEE-754 -// default rounding (to nearest, ties to even). +// This file implements single-precision soft-float addition. // //===----------------------------------------------------------------------===// diff --git a/lib/builtins/addtf3.c b/lib/builtins/addtf3.c index 570472a14..ac9b0cd60 100644 --- a/lib/builtins/addtf3.c +++ b/lib/builtins/addtf3.c @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements quad-precision soft-float addition with the IEEE-754 -// default rounding (to nearest, ties to even). +// This file implements quad-precision soft-float addition. // //===----------------------------------------------------------------------===// diff --git a/lib/builtins/arm/fp_mode.c b/lib/builtins/arm/fp_mode.c new file mode 100644 index 000000000..300b71935 --- /dev/null +++ b/lib/builtins/arm/fp_mode.c @@ -0,0 +1,59 @@ +//===----- lib/arm/fp_mode.c - Floaing-point mode utilities -------*- 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 +// +//===----------------------------------------------------------------------===// + +#include + +#include "../fp_mode.h" + +#define ARM_TONEAREST 0x0 +#define ARM_UPWARD 0x1 +#define ARM_DOWNWARD 0x2 +#define ARM_TOWARDZERO 0x3 +#define ARM_RMODE_MASK (ARM_TONEAREST | ARM_UPWARD | \ + ARM_DOWNWARD | ARM_TOWARDZERO) +#define ARM_RMODE_SHIFT 22 + +#define ARM_INEXACT 0x1000 + +#ifndef __ARM_FP +// For soft float targets, allow changing rounding mode by overriding the weak +// __arm_fe_default_rmode symbol. +FE_ROUND_MODE __attribute__((weak)) __arm_fe_default_rmode = FE_TONEAREST; +#endif + +FE_ROUND_MODE __fe_getround() { +#ifdef __ARM_FP + uint32_t fpscr; + __asm__ __volatile__("vmrs %0, fpscr" : "=r" (fpscr)); + fpscr = fpscr >> ARM_RMODE_SHIFT & ARM_RMODE_MASK; + switch (fpscr) { + case ARM_UPWARD: + return FE_UPWARD; + case ARM_DOWNWARD: + return FE_DOWNWARD; + case ARM_TOWARDZERO: + return FE_TOWARDZERO; + case ARM_TONEAREST: + default: + return FE_TONEAREST; + } +#else + return __arm_fe_default_rmode; +#endif +} + +int __fe_raise_inexact() { +#ifdef __ARM_FP + uint32_t fpscr; + __asm__ __volatile__("vmrs %0, fpscr" : "=r" (fpscr)); + __asm__ __volatile__("vmsr fpscr, %0" : : "ri" (fpscr | ARM_INEXACT)); + return 0; +#else + return 0; +#endif +} diff --git a/lib/builtins/fp_add_impl.inc b/lib/builtins/fp_add_impl.inc index da8639341..582324746 100644 --- a/lib/builtins/fp_add_impl.inc +++ b/lib/builtins/fp_add_impl.inc @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "fp_lib.h" +#include "fp_mode.h" static __inline fp_t __addXf3__(fp_t a, fp_t b) { rep_t aRep = toRep(a); @@ -149,9 +150,23 @@ static __inline fp_t __addXf3__(fp_t a, fp_t b) { // Perform the final rounding. The result may overflow to infinity, but // that is the correct result in that case. - if (roundGuardSticky > 0x4) - result++; - if (roundGuardSticky == 0x4) - result += result & 1; + switch (__fe_getround()) { + case FE_TONEAREST: + if (roundGuardSticky > 0x4) + result++; + if (roundGuardSticky == 0x4) + result += result & 1; + break; + case FE_DOWNWARD: + if (resultSign && roundGuardSticky) result++; + break; + case FE_UPWARD: + if (!resultSign && roundGuardSticky) result++; + break; + case FE_TOWARDZERO: + break; + } + if (roundGuardSticky) + __fe_raise_inexact(); return fromRep(result); } diff --git a/lib/builtins/fp_mode.c b/lib/builtins/fp_mode.c new file mode 100644 index 000000000..c1b6c1f6b --- /dev/null +++ b/lib/builtins/fp_mode.c @@ -0,0 +1,24 @@ +//===----- lib/fp_mode.c - Floaing-point environment mode utilities --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 +// +//===----------------------------------------------------------------------===// +// +// This file provides a default implementation of fp_mode.h for architectures +// that does not support or does not have an implementation of floating point +// environment mode. +// +//===----------------------------------------------------------------------===// + +#include "fp_mode.h" + +// IEEE-754 default rounding (to nearest, ties to even). +FE_ROUND_MODE __fe_getround() { + return FE_TONEAREST; +} + +int __fe_raise_inexact() { + return 0; +} diff --git a/lib/builtins/fp_mode.h b/lib/builtins/fp_mode.h new file mode 100644 index 000000000..51bec0431 --- /dev/null +++ b/lib/builtins/fp_mode.h @@ -0,0 +1,29 @@ +//===----- lib/fp_mode.h - Floaing-point environment mode utilities --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 +// +//===----------------------------------------------------------------------===// +// +// This file is not part of the interface of this library. +// +// This file defines an interface for accessing hardware floating point +// environment mode. +// +//===----------------------------------------------------------------------===// + +#ifndef FP_MODE +#define FP_MODE + +typedef enum { + FE_TONEAREST, + FE_DOWNWARD, + FE_UPWARD, + FE_TOWARDZERO +} FE_ROUND_MODE; + +FE_ROUND_MODE __fe_getround(); +int __fe_raise_inexact(); + +#endif // FP_MODE_H diff --git a/lib/builtins/subdf3.c b/lib/builtins/subdf3.c index 5346dbc97..2100fd39c 100644 --- a/lib/builtins/subdf3.c +++ b/lib/builtins/subdf3.c @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements double-precision soft-float subtraction with the -// IEEE-754 default rounding (to nearest, ties to even). +// This file implements double-precision soft-float subtraction. // //===----------------------------------------------------------------------===// diff --git a/lib/builtins/subsf3.c b/lib/builtins/subsf3.c index 85bde029b..ecfc24f7d 100644 --- a/lib/builtins/subsf3.c +++ b/lib/builtins/subsf3.c @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements single-precision soft-float subtraction with the -// IEEE-754 default rounding (to nearest, ties to even). +// This file implements single-precision soft-float subtraction. // //===----------------------------------------------------------------------===// diff --git a/lib/builtins/subtf3.c b/lib/builtins/subtf3.c index c96814692..3364c28f8 100644 --- a/lib/builtins/subtf3.c +++ b/lib/builtins/subtf3.c @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements quad-precision soft-float subtraction with the -// IEEE-754 default rounding (to nearest, ties to even). +// This file implements quad-precision soft-float subtraction. // //===----------------------------------------------------------------------===// diff --git a/test/builtins/Unit/addtf3_test.c b/test/builtins/Unit/addtf3_test.c index 8f00f6de7..492d93bb9 100644 --- a/test/builtins/Unit/addtf3_test.c +++ b/test/builtins/Unit/addtf3_test.c @@ -11,11 +11,12 @@ // //===----------------------------------------------------------------------===// -#include "int_lib.h" +#include #include #if __LDBL_MANT_DIG__ == 113 +#include "int_lib.h" #include "fp_test.h" // Returns: a + b @@ -74,6 +75,36 @@ int main() UINT64_C(0x61e58dd6c51eb77c))) return 1; +#if (defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP) + // Rounding mode tests on supported architectures + const long double m = 1234.0L, n = 0.01L; + + fesetround(FE_UPWARD); + if (test__addtf3(m, n, + UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d8))) + return 1; + + fesetround(FE_DOWNWARD); + if (test__addtf3(m, n, + UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; + + + fesetround(FE_TOWARDZERO); + if (test__addtf3(m, n, + UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; + + fesetround(FE_TONEAREST); + if (test__addtf3(m, n, + UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; +#endif + #else printf("skipped\n"); diff --git a/test/builtins/Unit/subtf3_test.c b/test/builtins/Unit/subtf3_test.c index bcf82e0c6..4953d1ceb 100644 --- a/test/builtins/Unit/subtf3_test.c +++ b/test/builtins/Unit/subtf3_test.c @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include #include #if __LDBL_MANT_DIG__ == 113 @@ -67,6 +68,35 @@ int main() UINT64_C(0xa44a7bca780a166c))) return 1; +#if (defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP) + // Rounding mode tests on supported architectures + const long double m = 1234.02L, n = 0.01L; + + fesetround(FE_UPWARD); + if (test__subtf3(m, n, + UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; + + fesetround(FE_DOWNWARD); + if (test__subtf3(m, n, + UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d6))) + return 1; + + fesetround(FE_TOWARDZERO); + if (test__subtf3(m, n, + UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d6))) + return 1; + + fesetround(FE_TONEAREST); + if (test__subtf3(m, n, + UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; +#endif + #else printf("skipped\n"); -- cgit v1.2.1