[compiler-rt] r342917 - [compiler-rt] [builtins] Add logb/logbf/logbl methods to compiler-rt to avoid libm dependencies when possible.

Jordan Rupprecht via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 24 13:39:19 PDT 2018


Author: rupprecht
Date: Mon Sep 24 13:39:19 2018
New Revision: 342917

URL: http://llvm.org/viewvc/llvm-project?rev=342917&view=rev
Log:
[compiler-rt] [builtins] Add logb/logbf/logbl methods to compiler-rt to avoid libm dependencies when possible.

Summary:
The complex division builtins (div?c3) use logb methods from libm to scale numbers during division and avoid rounding issues. However, these come from libm, meaning anyone that uses --rtlib=compiler-rt also has to include -lm. Implement logb* methods for standard ieee 754 floats so we can avoid -lm on those platforms, falling back to the old behavior (using either logb() or `__builtin_logb()`) when not supported.

These new methods are defined internally as `__compiler_rt_logb` so as not to conflict with the libm definitions in any way.

This fixes just the libm methods mentioned in PR32279 and PR28652. libc is still required, although that seems to not be an issue.

Note: this is proposed as an alternative to just adding -lm: D49330.

Reviewers: efriedma, compnerd, scanon, echristo

Reviewed By: echristo

Subscribers: jsji, echristo, nemanjai, dberris, mgorny, kbarton, delcypher, llvm-commits, #sanitizers

Differential Revision: https://reviews.llvm.org/D49514

Added:
    compiler-rt/trunk/test/builtins/Unit/compiler_rt_logb_test.c
    compiler-rt/trunk/test/builtins/Unit/compiler_rt_logbf_test.c
    compiler-rt/trunk/test/builtins/Unit/compiler_rt_logbl_test.c
Modified:
    compiler-rt/trunk/lib/builtins/divdc3.c
    compiler-rt/trunk/lib/builtins/divsc3.c
    compiler-rt/trunk/lib/builtins/divtc3.c
    compiler-rt/trunk/lib/builtins/fp_lib.h
    compiler-rt/trunk/lib/builtins/int_math.h
    compiler-rt/trunk/lib/builtins/ppc/divtc3.c

Modified: compiler-rt/trunk/lib/builtins/divdc3.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/builtins/divdc3.c?rev=342917&r1=342916&r2=342917&view=diff
==============================================================================
--- compiler-rt/trunk/lib/builtins/divdc3.c (original)
+++ compiler-rt/trunk/lib/builtins/divdc3.c Mon Sep 24 13:39:19 2018
@@ -12,6 +12,8 @@
  * ===----------------------------------------------------------------------===
  */
 
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
 #include "int_lib.h"
 #include "int_math.h"
 
@@ -21,7 +23,7 @@ COMPILER_RT_ABI Dcomplex
 __divdc3(double __a, double __b, double __c, double __d)
 {
     int __ilogbw = 0;
-    double __logbw = crt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d)));
+    double __logbw = __compiler_rt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d)));
     if (crt_isfinite(__logbw))
     {
         __ilogbw = (int)__logbw;

Modified: compiler-rt/trunk/lib/builtins/divsc3.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/builtins/divsc3.c?rev=342917&r1=342916&r2=342917&view=diff
==============================================================================
--- compiler-rt/trunk/lib/builtins/divsc3.c (original)
+++ compiler-rt/trunk/lib/builtins/divsc3.c Mon Sep 24 13:39:19 2018
@@ -12,6 +12,8 @@
  *===----------------------------------------------------------------------===
  */
 
+#define SINGLE_PRECISION
+#include "fp_lib.h"
 #include "int_lib.h"
 #include "int_math.h"
 
@@ -21,7 +23,8 @@ COMPILER_RT_ABI Fcomplex
 __divsc3(float __a, float __b, float __c, float __d)
 {
     int __ilogbw = 0;
-    float __logbw = crt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
+    float __logbw =
+        __compiler_rt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
     if (crt_isfinite(__logbw))
     {
         __ilogbw = (int)__logbw;

Modified: compiler-rt/trunk/lib/builtins/divtc3.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/builtins/divtc3.c?rev=342917&r1=342916&r2=342917&view=diff
==============================================================================
--- compiler-rt/trunk/lib/builtins/divtc3.c (original)
+++ compiler-rt/trunk/lib/builtins/divtc3.c Mon Sep 24 13:39:19 2018
@@ -12,6 +12,8 @@
  *===----------------------------------------------------------------------===
  */
 
+#define QUAD_PRECISION
+#include "fp_lib.h"
 #include "int_lib.h"
 #include "int_math.h"
 
@@ -21,7 +23,8 @@ COMPILER_RT_ABI Lcomplex
 __divtc3(long double __a, long double __b, long double __c, long double __d)
 {
     int __ilogbw = 0;
-    long double __logbw = crt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
+    long double __logbw =
+        __compiler_rt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
     if (crt_isfinite(__logbw))
     {
         __ilogbw = (int)__logbw;

Modified: compiler-rt/trunk/lib/builtins/fp_lib.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/builtins/fp_lib.h?rev=342917&r1=342916&r2=342917&view=diff
==============================================================================
--- compiler-rt/trunk/lib/builtins/fp_lib.h (original)
+++ compiler-rt/trunk/lib/builtins/fp_lib.h Mon Sep 24 13:39:19 2018
@@ -25,6 +25,7 @@
 #include <stdbool.h>
 #include <limits.h>
 #include "int_lib.h"
+#include "int_math.h"
 
 // x86_64 FreeBSD prior v9.3 define fixed-width types incorrectly in
 // 32-bit mode.
@@ -265,6 +266,62 @@ static __inline void wideRightShiftWithS
         *hi = 0;
     }
 }
+
+// Implements logb methods (logb, logbf, logbl) for IEEE-754. This avoids
+// pulling in a libm dependency from compiler-rt, but is not meant to replace
+// it (i.e. code calling logb() should get the one from libm, not this), hence
+// the __compiler_rt prefix.
+static __inline fp_t __compiler_rt_logbX(fp_t x) {
+  rep_t rep = toRep(x);
+  int exp = (rep & exponentMask) >> significandBits;
+
+  // Abnormal cases:
+  // 1) +/- inf returns +inf; NaN returns NaN
+  // 2) 0.0 returns -inf
+  if (exp == maxExponent) {
+    if (((rep & signBit) == 0) || (x != x)) {
+      return x;  // NaN or +inf: return x
+    } else {
+      return -x;  // -inf: return -x
+    }
+  } else if (x == 0.0) {
+    // 0.0: return -inf
+    return fromRep(infRep | signBit);
+  }
+
+  if (exp != 0) {
+    // Normal number
+    return exp - exponentBias;  // Unbias exponent
+  } else {
+    // Subnormal number; normalize and repeat
+    rep &= absMask;
+    const int shift = 1 - normalize(&rep);
+    exp = (rep & exponentMask) >> significandBits;
+    return exp - exponentBias - shift;  // Unbias exponent
+  }
+}
+#endif
+
+#if defined(SINGLE_PRECISION)
+static __inline fp_t __compiler_rt_logbf(fp_t x) {
+  return __compiler_rt_logbX(x);
+}
+#elif defined(DOUBLE_PRECISION)
+static __inline fp_t __compiler_rt_logb(fp_t x) {
+  return __compiler_rt_logbX(x);
+}
+#elif defined(QUAD_PRECISION)
+  #if defined(CRT_LDBL_128BIT)
+static __inline fp_t __compiler_rt_logbl(fp_t x) {
+  return __compiler_rt_logbX(x);
+}
+  #else
+// The generic implementation only works for ieee754 floating point. For other
+// floating point types, continue to rely on the libm implementation for now.
+static __inline long double __compiler_rt_logbl(long double x) {
+  return crt_logbl(x);
+}
+  #endif
 #endif
 
 #endif // FP_LIB_HEADER

Modified: compiler-rt/trunk/lib/builtins/int_math.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/builtins/int_math.h?rev=342917&r1=342916&r2=342917&view=diff
==============================================================================
--- compiler-rt/trunk/lib/builtins/int_math.h (original)
+++ compiler-rt/trunk/lib/builtins/int_math.h Mon Sep 24 13:39:19 2018
@@ -92,12 +92,8 @@
 #endif
 
 #if defined(_MSC_VER) && !defined(__clang__)
-#define crt_logb(x) logb((x))
-#define crt_logbf(x) logbf((x))
 #define crt_logbl(x) logbl((x))
 #else
-#define crt_logb(x) __builtin_logb((x))
-#define crt_logbf(x) __builtin_logbf((x))
 #define crt_logbl(x) __builtin_logbl((x))
 #endif
 

Modified: compiler-rt/trunk/lib/builtins/ppc/divtc3.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/builtins/ppc/divtc3.c?rev=342917&r1=342916&r2=342917&view=diff
==============================================================================
--- compiler-rt/trunk/lib/builtins/ppc/divtc3.c (original)
+++ compiler-rt/trunk/lib/builtins/ppc/divtc3.c Mon Sep 24 13:39:19 2018
@@ -4,6 +4,11 @@
 
 #include "DD.h"
 #include "../int_math.h"
+// Use DOUBLE_PRECISION because the soft-fp method we use is logb (on the upper
+// half of the long doubles), even though this file defines complex division for
+// 128-bit floats.
+#define DOUBLE_PRECISION
+#include "../fp_lib.h"
 
 #if !defined(CRT_INFINITY) && defined(HUGE_VAL)
 #define CRT_INFINITY HUGE_VAL
@@ -21,9 +26,10 @@ __divtc3(long double a, long double b, l
 	DD dDD = { .ld = d };
 	
 	int ilogbw = 0;
-	const double logbw = crt_logb(crt_fmax(crt_fabs(cDD.s.hi), crt_fabs(dDD.s.hi) ));
-	
-	if (crt_isfinite(logbw))
+	const double logbw = __compiler_rt_logb(
+		crt_fmax(crt_fabs(cDD.s.hi), crt_fabs(dDD.s.hi)));
+
+        if (crt_isfinite(logbw))
 	{
 		ilogbw = (int)logbw;
 		

Added: compiler-rt/trunk/test/builtins/Unit/compiler_rt_logb_test.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/builtins/Unit/compiler_rt_logb_test.c?rev=342917&view=auto
==============================================================================
--- compiler-rt/trunk/test/builtins/Unit/compiler_rt_logb_test.c (added)
+++ compiler-rt/trunk/test/builtins/Unit/compiler_rt_logb_test.c Mon Sep 24 13:39:19 2018
@@ -0,0 +1,63 @@
+// RUN: %clang_builtins %s %librt -lm -o %t && %run %t
+//===-- compiler_rt_logb_test.c - Test __compiler_rt_logb -----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file checks __compiler_rt_logb from the compiler_rt library for
+// conformance against libm.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include <math.h>
+#include <stdio.h>
+#include "fp_lib.h"
+
+int test__compiler_rt_logb(fp_t x) {
+  fp_t crt_value = __compiler_rt_logb(x);
+  fp_t libm_value = logb(x);
+  // Compare actual rep, e.g. to avoid NaN != the same NaN
+  if (toRep(crt_value) != toRep(libm_value)) {
+    printf("error: in __compiler_rt_logb(%a [%lX]) = %a [%lX] !=  %a [%lX]\n",
+           x, toRep(x), crt_value, toRep(crt_value), libm_value,
+           toRep(libm_value));
+    return 1;
+  }
+  return 0;
+}
+
+double cases[] = {
+    1.e-6, -1.e-6, NAN, -NAN, INFINITY, -INFINITY, -1,
+    -0.0,  0.0,    1,   -2,   2,        -0.5,      0.5,
+};
+
+int main() {
+  const unsigned N = sizeof(cases) / sizeof(cases[0]);
+  unsigned i;
+  for (i = 0; i < N; ++i) {
+    if (test__compiler_rt_logb(cases[i])) return 1;
+  }
+
+  // Test a moving 1 bit, especially to handle denormal values.
+  // Test the negation as well.
+  rep_t x = signBit;
+  while (x) {
+    if (test__compiler_rt_logb(fromRep(x))) return 1;
+    if (test__compiler_rt_logb(fromRep(signBit ^ x))) return 1;
+    x >>= 1;
+  }
+  // Also try a couple moving ones
+  x = signBit | (signBit >> 1) | (signBit >> 2);
+  while (x) {
+    if (test__compiler_rt_logb(fromRep(x))) return 1;
+    if (test__compiler_rt_logb(fromRep(signBit ^ x))) return 1;
+    x >>= 1;
+  }
+
+  return 0;
+}

Added: compiler-rt/trunk/test/builtins/Unit/compiler_rt_logbf_test.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/builtins/Unit/compiler_rt_logbf_test.c?rev=342917&view=auto
==============================================================================
--- compiler-rt/trunk/test/builtins/Unit/compiler_rt_logbf_test.c (added)
+++ compiler-rt/trunk/test/builtins/Unit/compiler_rt_logbf_test.c Mon Sep 24 13:39:19 2018
@@ -0,0 +1,63 @@
+// RUN: %clang_builtins %s %librt -lm -o %t && %run %t
+//===-- compiler_rt_logbf_test.c - Test __compiler_rt_logbf ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file checks __compiler_rt_logbf from the compiler_rt library for
+// conformance against libm.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include <math.h>
+#include <stdio.h>
+#include "fp_lib.h"
+
+int test__compiler_rt_logbf(fp_t x) {
+  fp_t crt_value = __compiler_rt_logbf(x);
+  fp_t libm_value = logbf(x);
+  // Compare actual rep, e.g. to avoid NaN != the same NaN
+  if (toRep(crt_value) != toRep(libm_value)) {
+    printf("error: in __compiler_rt_logb(%a [%X]) = %a [%X] !=  %a [%X]\n", x,
+           toRep(x), crt_value, toRep(crt_value), libm_value,
+           toRep(libm_value));
+    return 1;
+  }
+  return 0;
+}
+
+double cases[] = {
+    1.e-6, -1.e-6, NAN, -NAN, INFINITY, -INFINITY, -1,
+    -0.0,  0.0,    1,   -2,   2,        -0.5,      0.5,
+};
+
+int main() {
+  const unsigned N = sizeof(cases) / sizeof(cases[0]);
+  unsigned i;
+  for (i = 0; i < N; ++i) {
+    if (test__compiler_rt_logbf(cases[i])) return 1;
+  }
+
+  // Test a moving 1 bit, especially to handle denormal values.
+  // Test the negation as well.
+  rep_t x = signBit;
+  while (x) {
+    if (test__compiler_rt_logbf(fromRep(x))) return 1;
+    if (test__compiler_rt_logbf(fromRep(signBit ^ x))) return 1;
+    x >>= 1;
+  }
+  // Also try a couple moving ones
+  x = signBit | (signBit >> 1) | (signBit >> 2);
+  while (x) {
+    if (test__compiler_rt_logbf(fromRep(x))) return 1;
+    if (test__compiler_rt_logbf(fromRep(signBit ^ x))) return 1;
+    x >>= 1;
+  }
+
+  return 0;
+}

Added: compiler-rt/trunk/test/builtins/Unit/compiler_rt_logbl_test.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/builtins/Unit/compiler_rt_logbl_test.c?rev=342917&view=auto
==============================================================================
--- compiler-rt/trunk/test/builtins/Unit/compiler_rt_logbl_test.c (added)
+++ compiler-rt/trunk/test/builtins/Unit/compiler_rt_logbl_test.c Mon Sep 24 13:39:19 2018
@@ -0,0 +1,79 @@
+// RUN: %clang_builtins %s %librt -lm -o %t && %run %t
+//===-- compiler_rt_logbl_test.c - Test __compiler_rt_logbl ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file checks __compiler_rt_logbl from the compiler_rt library for
+// conformance against libm.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include <math.h>
+#include <stdio.h>
+#include "fp_lib.h"
+#include "int_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+
+int test__compiler_rt_logbl(fp_t x) {
+  fp_t crt_value = __compiler_rt_logbl(x);
+  fp_t libm_value = logbl(x);
+  // Compare actual rep, e.g. to avoid NaN != the same NaN
+  if (toRep(crt_value) != toRep(libm_value)) {
+    // Split expected values into two for printf
+    twords x_t, crt_value_t, libm_value_t;
+    x_t.all = toRep(x);
+    crt_value_t.all = toRep(crt_value);
+    libm_value_t.all = toRep(libm_value);
+    printf(
+        "error: in __compiler_rt_logb(%a [%llX %llX]) = %a [%llX %llX] !=  %a "
+        "[%llX %llX]\n",
+        x, x_t.s.high, x_t.s.low, crt_value, crt_value_t.s.high,
+        crt_value_t.s.low, libm_value, libm_value_t.s.high, libm_value_t.s.low);
+    return 1;
+  }
+  return 0;
+}
+
+double cases[] = {
+    1.e-6, -1.e-6, NAN, -NAN, INFINITY, -INFINITY, -1,
+    -0.0,  0.0,    1,   -2,   2,        -0.5,      0.5,
+};
+
+#endif
+
+int main() {
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+  const unsigned N = sizeof(cases) / sizeof(cases[0]);
+  unsigned i;
+  for (i = 0; i < N; ++i) {
+    if (test__compiler_rt_logbl(cases[i])) return 1;
+  }
+
+  // Test a moving 1 bit, especially to handle denormal values.
+  // Test the negation as well.
+  rep_t x = signBit;
+  while (x) {
+    if (test__compiler_rt_logbl(fromRep(x))) return 1;
+    if (test__compiler_rt_logbl(fromRep(signBit ^ x))) return 1;
+    x >>= 1;
+  }
+  // Also try a couple moving ones
+  x = signBit | (signBit >> 1) | (signBit >> 2);
+  while (x) {
+    if (test__compiler_rt_logbl(fromRep(x))) return 1;
+    if (test__compiler_rt_logbl(fromRep(signBit ^ x))) return 1;
+    x >>= 1;
+  }
+#else
+  printf("skipped\n");
+#endif
+
+  return 0;
+}




More information about the llvm-commits mailing list