summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYi Kong <yikong@google.com>2019-09-05 01:05:05 +0000
committerYi Kong <yikong@google.com>2019-09-05 01:05:05 +0000
commit2dd05b302ecefead0c849efdadbe3a48b2492b94 (patch)
treea2042c378f07cd4808682471bd263cda8afeeaca
parent155ed45405e7ed61cd2e10fc114b31ca9525b8aa (diff)
downloadcompiler-rt-2dd05b302ecefead0c849efdadbe3a48b2492b94.tar.gz
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
-rw-r--r--lib/builtins/CMakeLists.txt3
-rw-r--r--lib/builtins/aarch64/fp_mode.c59
-rw-r--r--lib/builtins/adddf3.c3
-rw-r--r--lib/builtins/addsf3.c3
-rw-r--r--lib/builtins/addtf3.c3
-rw-r--r--lib/builtins/arm/fp_mode.c59
-rw-r--r--lib/builtins/fp_add_impl.inc23
-rw-r--r--lib/builtins/fp_mode.c24
-rw-r--r--lib/builtins/fp_mode.h29
-rw-r--r--lib/builtins/subdf3.c3
-rw-r--r--lib/builtins/subsf3.c3
-rw-r--r--lib/builtins/subtf3.c3
-rw-r--r--test/builtins/Unit/addtf3_test.c33
-rw-r--r--test/builtins/Unit/subtf3_test.c30
14 files changed, 261 insertions, 17 deletions
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 <stdint.h>
+
+#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 <stdint.h>
+
+#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 <fenv.h>
#include <stdio.h>
#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 <fenv.h>
#include <stdio.h>
#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");