Izaron updated this revision to Diff 470962.
Izaron added a comment.

Add test for min/max value. Fix comment for ilog.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136568/new/

https://reviews.llvm.org/D136568

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/Basic/Builtins.def
  clang/lib/AST/ExprConstant.cpp
  clang/test/Sema/constant-builtins-ilogb.cpp
  llvm/include/llvm/ADT/APFloat.h
  llvm/lib/Support/APFloat.cpp
  llvm/unittests/ADT/APFloatTest.cpp

Index: llvm/unittests/ADT/APFloatTest.cpp
===================================================================
--- llvm/unittests/ADT/APFloatTest.cpp
+++ llvm/unittests/ADT/APFloatTest.cpp
@@ -3250,46 +3250,99 @@
 }
 
 TEST(APFloatTest, ilogb) {
-  EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), false)));
-  EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), true)));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1024")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1023")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "-0x1.ffffffffffffep-1023")));
-  EXPECT_EQ(-51, ilogb(APFloat(APFloat::IEEEdouble(), "0x1p-51")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1023")));
-  EXPECT_EQ(-2, ilogb(APFloat(APFloat::IEEEdouble(), "0x0.ffffp-1")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.fffep-1023")));
-  EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble(), false)));
-  EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble(), true)));
-
-
-  EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+0")));
-  EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle(), "-0x1p+0")));
-  EXPECT_EQ(42, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+42")));
-  EXPECT_EQ(-42, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p-42")));
-
-  EXPECT_EQ(APFloat::IEK_Inf,
-            ilogb(APFloat::getInf(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_Inf,
-            ilogb(APFloat::getInf(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(APFloat::IEK_Zero,
-            ilogb(APFloat::getZero(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_Zero,
-            ilogb(APFloat::getZero(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(APFloat::IEK_NaN,
-            ilogb(APFloat::getNaN(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_NaN,
-            ilogb(APFloat::getSNaN(APFloat::IEEEsingle(), false)));
-
-  EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle(), true)));
-
-  EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(-126,
-            ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(-126,
-            ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true)));
+  int Result;
+
+  EXPECT_EQ(ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), false), Result),
+            APFloat::opOK);
+  EXPECT_EQ(-1074, Result);
+  EXPECT_EQ(ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), true), Result),
+            APFloat::opOK);
+  EXPECT_EQ(-1074, Result);
+  EXPECT_EQ(
+      ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1024"), Result),
+      APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(
+      ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1023"), Result),
+      APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(
+      ilogb(APFloat(APFloat::IEEEdouble(), "-0x1.ffffffffffffep-1023"), Result),
+      APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x1p-51"), Result),
+            APFloat::opOK);
+  EXPECT_EQ(-51, Result);
+  EXPECT_EQ(
+      ilogb(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1023"), Result),
+      APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x0.ffffp-1"), Result),
+            APFloat::opOK);
+  EXPECT_EQ(-2, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x1.fffep-1023"), Result),
+            APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat::getLargest(APFloat::IEEEdouble(), false), Result),
+            APFloat::opOK);
+  EXPECT_EQ(1023, Result);
+  EXPECT_EQ(ilogb(APFloat::getLargest(APFloat::IEEEdouble(), true), Result),
+            APFloat::opOK);
+  EXPECT_EQ(1023, Result);
+
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+0"), Result),
+            APFloat::opOK);
+  EXPECT_EQ(0, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "-0x1p+0"), Result),
+            APFloat::opOK);
+  EXPECT_EQ(0, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+42"), Result),
+            APFloat::opOK);
+  EXPECT_EQ(42, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "0x1p-42"), Result),
+            APFloat::opOK);
+  EXPECT_EQ(-42, Result);
+
+  EXPECT_EQ(ilogb(APFloat::getInf(APFloat::IEEEsingle(), false), Result),
+            APFloat::opInvalidOp);
+  EXPECT_EQ(APFloat::IEK_Inf, Result);
+  EXPECT_EQ(ilogb(APFloat::getInf(APFloat::IEEEsingle(), true), Result),
+            APFloat::opInvalidOp);
+  EXPECT_EQ(APFloat::IEK_Inf, Result);
+  EXPECT_EQ(ilogb(APFloat::getZero(APFloat::IEEEsingle(), false), Result),
+            APFloat::opInvalidOp);
+  EXPECT_EQ(APFloat::IEK_Zero, Result);
+  EXPECT_EQ(ilogb(APFloat::getZero(APFloat::IEEEsingle(), true), Result),
+            APFloat::opInvalidOp);
+  EXPECT_EQ(APFloat::IEK_Zero, Result);
+  EXPECT_EQ(ilogb(APFloat::getNaN(APFloat::IEEEsingle(), false), Result),
+            APFloat::opInvalidOp);
+  EXPECT_EQ(APFloat::IEK_NaN, Result);
+  EXPECT_EQ(ilogb(APFloat::getSNaN(APFloat::IEEEsingle(), false), Result),
+            APFloat::opInvalidOp);
+  EXPECT_EQ(APFloat::IEK_NaN, Result);
+
+  EXPECT_EQ(ilogb(APFloat::getLargest(APFloat::IEEEsingle(), false), Result),
+            APFloat::opOK);
+  EXPECT_EQ(127, Result);
+  EXPECT_EQ(ilogb(APFloat::getLargest(APFloat::IEEEsingle(), true), Result),
+            APFloat::opOK);
+  EXPECT_EQ(127, Result);
+
+  EXPECT_EQ(ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), false), Result),
+            APFloat::opOK);
+  EXPECT_EQ(-149, Result);
+  EXPECT_EQ(ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), true), Result),
+            APFloat::opOK);
+  EXPECT_EQ(-149, Result);
+  EXPECT_EQ(ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false),
+                  Result),
+            APFloat::opOK);
+  EXPECT_EQ(-126, Result);
+  EXPECT_EQ(ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true),
+                  Result),
+            APFloat::opOK);
+  EXPECT_EQ(-126, Result);
 }
 
 TEST(APFloatTest, scalbn) {
Index: llvm/lib/Support/APFloat.cpp
===================================================================
--- llvm/lib/Support/APFloat.cpp
+++ llvm/lib/Support/APFloat.cpp
@@ -4242,22 +4242,37 @@
   APInt::tcSetBit(significandParts(), semantics->precision - 2);
 }
 
-int ilogb(const IEEEFloat &Arg) {
-  if (Arg.isNaN())
-    return IEEEFloat::IEK_NaN;
-  if (Arg.isZero())
-    return IEEEFloat::IEK_Zero;
-  if (Arg.isInfinity())
-    return IEEEFloat::IEK_Inf;
-  if (!Arg.isDenormal())
-    return Arg.exponent;
+IEEEFloat::opStatus ilogb(const IEEEFloat &Arg, int &Result) {
+  if (Arg.isNaN()) {
+    Result = IEEEFloat::IEK_NaN;
+    return IEEEFloat::opInvalidOp;
+  }
+  if (Arg.isZero()) {
+    Result = IEEEFloat::IEK_Zero;
+    return IEEEFloat::opInvalidOp;
+  }
+  if (Arg.isInfinity()) {
+    Result = IEEEFloat::IEK_Inf;
+    return IEEEFloat::opInvalidOp;
+  }
+  if (!Arg.isDenormal()) {
+    Result = Arg.exponent;
+    return IEEEFloat::opOK;
+  }
 
   IEEEFloat Normalized(Arg);
   int SignificandBits = Arg.getSemantics().precision - 1;
 
   Normalized.exponent += SignificandBits;
   Normalized.normalize(IEEEFloat::rmNearestTiesToEven, lfExactlyZero);
-  return Normalized.exponent - SignificandBits;
+  Result = Normalized.exponent - SignificandBits;
+  return IEEEFloat::opOK;
+}
+
+int ilogb(const IEEEFloat &Arg) {
+  int Result;
+  ilogb(Arg, Result);
+  return Result;
 }
 
 IEEEFloat scalbn(IEEEFloat X, int Exp, IEEEFloat::roundingMode RoundingMode) {
Index: llvm/include/llvm/ADT/APFloat.h
===================================================================
--- llvm/include/llvm/ADT/APFloat.h
+++ llvm/include/llvm/ADT/APFloat.h
@@ -443,16 +443,19 @@
   /// return true.
   bool getExactInverse(APFloat *inv) const;
 
-  /// Returns the exponent of the internal representation of the APFloat.
+  /// Calculates the exponent of the internal representation of the APFloat
+  /// and saves the result in `Result`.
   ///
   /// Because the radix of APFloat is 2, this is equivalent to floor(log2(x)).
-  /// For special APFloat values, this returns special error codes:
+  /// For special APFloat values, this saves special error codes to `Result`:
   ///
   ///   NaN -> \c IEK_NaN
   ///   0   -> \c IEK_Zero
   ///   Inf -> \c IEK_Inf
   ///
-  friend int ilogb(const IEEEFloat &Arg);
+  /// and returns `opInvalidOp`. Returns `opOK` for other values.
+  ///
+  friend opStatus ilogb(const IEEEFloat &Arg, int &Result);
 
   /// Returns: X * 2^Exp for integral exponents.
   friend IEEEFloat scalbn(IEEEFloat X, int Exp, roundingMode);
@@ -597,6 +600,7 @@
 };
 
 hash_code hash_value(const IEEEFloat &Arg);
+IEEEFloat::opStatus ilogb(const IEEEFloat &Arg, int &Result);
 int ilogb(const IEEEFloat &Arg);
 IEEEFloat scalbn(IEEEFloat X, int Exp, IEEEFloat::roundingMode);
 IEEEFloat frexp(const IEEEFloat &Val, int &Exp, IEEEFloat::roundingMode RM);
@@ -1253,6 +1257,9 @@
   }
 
   friend hash_code hash_value(const APFloat &Arg);
+  friend opStatus ilogb(const APFloat &Arg, int &Result) {
+    return ilogb(Arg.getIEEE(), Result);
+  }
   friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); }
   friend APFloat scalbn(APFloat X, int Exp, roundingMode RM);
   friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM);
Index: clang/test/Sema/constant-builtins-ilogb.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/constant-builtins-ilogb.cpp
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+constexpr double NaN = __builtin_nan("");
+constexpr double Inf = __builtin_inf();
+constexpr double NegInf = -__builtin_inf();
+
+#define ILOGB_TEST_SPECIAL_NUMBERS(T, FUNC)                \
+    static_assert(!__builtin_constant_p(FUNC(T(0.0))));    \
+    static_assert(!__builtin_constant_p(FUNC(T(-0.0))));   \
+    static_assert(!__builtin_constant_p(FUNC(T(NaN))));    \
+    static_assert(!__builtin_constant_p(FUNC(T(Inf))));    \
+    static_assert(!__builtin_constant_p(FUNC(T(NegInf))));
+
+#define ILOGB_TEST_POWERS_OF_TWO(T, FUNC) \
+    static_assert(0 == FUNC(T(1.0)));     \
+    static_assert(0 == FUNC(T(-1.0)));    \
+    static_assert(1 == FUNC(T(2.0)));     \
+    static_assert(1 == FUNC(T(-2.0)));    \
+    static_assert(2 == FUNC(T(4.0)));     \
+    static_assert(2 == FUNC(T(-4.0)));    \
+    static_assert(3 == FUNC(T(8.0)));     \
+    static_assert(3 == FUNC(T(-8.0)));    \
+    static_assert(4 == FUNC(T(16.0)));    \
+    static_assert(4 == FUNC(T(-16.0)));   \
+    static_assert(5 == FUNC(T(32.0)));    \
+    static_assert(5 == FUNC(T(-32.0)));
+
+#define ILOGB_TEST_SOME_INTEGERS(T, FUNC) \
+    static_assert(1 == FUNC(T(3.0)));     \
+    static_assert(1 == FUNC(T(-3.0)));    \
+    static_assert(2 == FUNC(T(7.0)));     \
+    static_assert(2 == FUNC(T(-7.0)));    \
+    static_assert(3 == FUNC(T(10.0)));    \
+    static_assert(3 == FUNC(T(-10.0)));   \
+    static_assert(4 == FUNC(T(31.0)));    \
+    static_assert(4 == FUNC(T(-31.0)));   \
+    static_assert(5 == FUNC(T(55.0)));    \
+    static_assert(5 == FUNC(T(-55.0)));
+
+#define LIST_ILOGB_TESTS(T, FUNC)       \
+    ILOGB_TEST_SPECIAL_NUMBERS(T, FUNC) \
+    ILOGB_TEST_POWERS_OF_TWO(T, FUNC)   \
+    ILOGB_TEST_SOME_INTEGERS(T, FUNC)
+
+LIST_ILOGB_TESTS(double, __builtin_ilogb)
+LIST_ILOGB_TESTS(float, __builtin_ilogbf)
+LIST_ILOGB_TESTS((long double), __builtin_ilogbl)
+#ifdef __FLOAT128__
+LIST_ILOGB_TESTS(__float128, __builtin_ilogbf128)
+#endif
+
+// assert smallest subnormal and largest finite numbers
+static_assert(__builtin_ilogbf(1.40129846E-45f) == -149);
+static_assert(__builtin_ilogbf(3.40282347E+38f) == 127);
+
+static_assert(__builtin_ilogb(4.9406564584124654E-324) == -1074);
+static_assert(__builtin_ilogb(1.7976931348623157E+308) == 1023);
+
+static_assert(__builtin_ilogbl(3.64519953188247460253E-4951L) == -16445);
+static_assert(__builtin_ilogbl(1.18973149535723176502E+4932L) == 16383);
+
+#ifdef __FLOAT128__
+static_assert(__builtin_ilogbf128(6.47517511943802511092443895822764655E-4966Q) == -16494);
+static_assert(__builtin_ilogbf128(1.18973149535723176508575932662800702E+4932Q) == 16383);
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -7349,6 +7349,13 @@
   return true;
 }
 
+// A call to a C standard library function is a non-constant library call
+// ([defns.nonconst.libcall]) if it raises a floating-point exception other
+// than FE_INEXACT.
+static bool isConstantOpStatus(APFloat::opStatus St) {
+  return (St & ~APFloat::opInexact) == 0;
+}
+
 template <class Derived>
 class ExprEvaluatorBase
   : public ConstStmtVisitor<Derived, bool> {
@@ -12433,6 +12440,23 @@
       return false;
     return Success(DidOverflow, E);
   }
+  case Builtin::BI__builtin_ilogb:
+  case Builtin::BI__builtin_ilogbf:
+  case Builtin::BI__builtin_ilogbl:
+  case Builtin::BI__builtin_ilogbf128: {
+    APFloat F(0.0);
+    if (!EvaluateFloat(E->getArg(0), F, Info))
+      return false;
+
+    int Ilogb;
+    if (APFloat::opStatus St = ilogb(F, Ilogb); !isConstantOpStatus(St))
+      return false;
+
+    APSInt Logb(llvm::APInt(32, Ilogb, /*isSigned=*/true),
+                /*isUnsigned=*/false);
+    Result = APValue(std::move(Logb));
+    return true;
+  }
   }
 }
 
Index: clang/include/clang/Basic/Builtins.def
===================================================================
--- clang/include/clang/Basic/Builtins.def
+++ clang/include/clang/Basic/Builtins.def
@@ -273,10 +273,10 @@
 BUILTIN(__builtin_hypotf, "fff"  , "Fne")
 BUILTIN(__builtin_hypotl, "LdLdLd", "Fne")
 BUILTIN(__builtin_hypotf128, "LLdLLdLLd", "Fne")
-BUILTIN(__builtin_ilogb , "id", "Fne")
-BUILTIN(__builtin_ilogbf, "if", "Fne")
-BUILTIN(__builtin_ilogbl, "iLd", "Fne")
-BUILTIN(__builtin_ilogbf128, "iLLd", "Fne")
+BUILTIN(__builtin_ilogb , "id", "FneE")
+BUILTIN(__builtin_ilogbf, "if", "FneE")
+BUILTIN(__builtin_ilogbl, "iLd", "FneE")
+BUILTIN(__builtin_ilogbf128, "iLLd", "FneE")
 BUILTIN(__builtin_lgamma , "dd", "Fn")
 BUILTIN(__builtin_lgammaf, "ff", "Fn")
 BUILTIN(__builtin_lgammal, "LdLd", "Fn")
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -4698,6 +4698,7 @@
 * ``__builtin_fmax``
 * ``__builtin_fmin``
 * ``__builtin_fpclassify``
+* ``__builtin_ilogb``
 * ``__builtin_inf``
 * ``__builtin_isinf``
 * ``__builtin_isinf_sign``
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to