[clang] f4066fa - [clang] Use constant rounding mode for floating literals (#90877)

via cfe-commits cfe-commits at lists.llvm.org
Thu May 16 22:06:37 PDT 2024


Author: Serge Pavlov
Date: 2024-05-17T12:06:34+07:00
New Revision: f4066fa2dd21c65bf0e24a479634c9a2d276cf8e

URL: https://github.com/llvm/llvm-project/commit/f4066fa2dd21c65bf0e24a479634c9a2d276cf8e
DIFF: https://github.com/llvm/llvm-project/commit/f4066fa2dd21c65bf0e24a479634c9a2d276cf8e.diff

LOG: [clang] Use constant rounding mode for floating literals (#90877)

Conversion of floating-point literal to binary representation must be
made using constant rounding mode, which can be changed using pragma
FENV_ROUND. For example, the literal "0.1F" should be representes by
either 0.099999994 or 0.100000001 depending on the rounding direction.

Added: 
    

Modified: 
    clang/include/clang/Lex/LiteralSupport.h
    clang/lib/Lex/LiteralSupport.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/test/AST/const-fpfeatures.c
    clang/test/AST/const-fpfeatures.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h
index 2ed42d1c5f9aa..705021fcfa5b1 100644
--- a/clang/include/clang/Lex/LiteralSupport.h
+++ b/clang/include/clang/Lex/LiteralSupport.h
@@ -118,12 +118,10 @@ class NumericLiteralParser {
   /// bits of the result and return true.  Otherwise, return false.
   bool GetIntegerValue(llvm::APInt &Val);
 
-  /// GetFloatValue - Convert this numeric literal to a floating value, using
-  /// the specified APFloat fltSemantics (specifying float, double, etc).
-  /// The optional bool isExact (passed-by-reference) has its value
-  /// set to true if the returned APFloat can represent the number in the
-  /// literal exactly, and false otherwise.
-  llvm::APFloat::opStatus GetFloatValue(llvm::APFloat &Result);
+  /// Convert this numeric literal to a floating value, using the specified
+  /// APFloat fltSemantics (specifying float, double, etc) and rounding mode.
+  llvm::APFloat::opStatus GetFloatValue(llvm::APFloat &Result,
+                                        llvm::RoundingMode RM);
 
   /// GetFixedPointValue - Convert this numeric literal value into a
   /// scaled integer that represents this value. Returns true if an overflow

diff  --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index 9c0cbea5052cb..3df0391bdda77 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -1520,7 +1520,8 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
 }
 
 llvm::APFloat::opStatus
-NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
+NumericLiteralParser::GetFloatValue(llvm::APFloat &Result,
+                                    llvm::RoundingMode RM) {
   using llvm::APFloat;
 
   unsigned n = std::min(SuffixBegin - ThisTokBegin, ThisTokEnd - ThisTokBegin);
@@ -1534,8 +1535,7 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
     Str = Buffer;
   }
 
-  auto StatusOrErr =
-      Result.convertFromString(Str, APFloat::rmNearestTiesToEven);
+  auto StatusOrErr = Result.convertFromString(Str, RM);
   assert(StatusOrErr && "Invalid floating point representation");
   return !errorToBool(StatusOrErr.takeError()) ? *StatusOrErr
                                                : APFloat::opInvalidOp;

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 274e1fb183534..e0aae6333e1a1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3699,7 +3699,10 @@ static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
   using llvm::APFloat;
   APFloat Val(Format);
 
-  APFloat::opStatus result = Literal.GetFloatValue(Val);
+  llvm::RoundingMode RM = S.CurFPFeatures.getRoundingMode();
+  if (RM == llvm::RoundingMode::Dynamic)
+    RM = llvm::RoundingMode::NearestTiesToEven;
+  APFloat::opStatus result = Literal.GetFloatValue(Val, RM);
 
   // Overflow is always an error, but underflow is only an error if
   // we underflowed to zero (APFloat reports denormals as underflow).

diff  --git a/clang/test/AST/const-fpfeatures.c b/clang/test/AST/const-fpfeatures.c
index 083350fdc8ce6..8dc3221b0638a 100644
--- a/clang/test/AST/const-fpfeatures.c
+++ b/clang/test/AST/const-fpfeatures.c
@@ -19,6 +19,9 @@ float FI1u = 0xFFFFFFFFU;
 float _Complex C1u = C0;
 // CHECK: @C1u = {{.*}} { float, float } { float 0x3FF0000020000000, float 0x3FF0000020000000 }
 
+float FLu = 0.1F;
+// CHECK: @FLu = {{.*}} float 0x3FB99999A0000000
+
 
 #pragma STDC FENV_ROUND FE_DOWNWARD
 
@@ -35,3 +38,6 @@ float FI1d = 0xFFFFFFFFU;
 
 float _Complex C1d = C0;
 // CHECK: @C1d = {{.*}} { float, float } { float 1.000000e+00, float 1.000000e+00 }
+
+float FLd = 0.1F;
+// CHECK: @FLd = {{.*}} float 0x3FB9999980000000

diff  --git a/clang/test/AST/const-fpfeatures.cpp b/clang/test/AST/const-fpfeatures.cpp
index 95eb613df7f07..5e903c8c0e874 100644
--- a/clang/test/AST/const-fpfeatures.cpp
+++ b/clang/test/AST/const-fpfeatures.cpp
@@ -79,3 +79,108 @@ float V7 = []() -> float {
   0x0.000001p0F);
 }();
 // CHECK: @V7 = {{.*}} float 1.000000e+00
+
+#pragma STDC FENV_ROUND FE_DYNAMIC
+
+template<float V> struct L {
+  constexpr L() : value(V) {}
+  float value;
+};
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+L<0.1F> val_d;
+// CHECK: @val_d = {{.*}} { float 0x3FB9999980000000 }
+
+#pragma STDC FENV_ROUND FE_UPWARD
+L<0.1F> val_u;
+// CHECK: @val_u = {{.*}} { float 0x3FB99999A0000000 }
+
+
+// Check literals in macros.
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+#define CONSTANT_0_1 0.1F
+
+#pragma STDC FENV_ROUND FE_UPWARD
+float C1_ru = CONSTANT_0_1;
+// CHECK: @C1_ru = {{.*}} float 0x3FB99999A0000000
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+float C1_rd = CONSTANT_0_1;
+// CHECK: @C1_rd = {{.*}} float 0x3FB9999980000000
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+#define PRAGMA(x) _Pragma(#x)
+#define CONSTANT_0_1_RM(v, rm) ([](){ PRAGMA(STDC FENV_ROUND rm); return v; }())
+
+#pragma STDC FENV_ROUND FE_UPWARD
+float C2_rd = CONSTANT_0_1_RM(0.1F, FE_DOWNWARD);
+float C2_ru = CONSTANT_0_1_RM(0.1F, FE_UPWARD);
+// CHECK: @C2_rd = {{.*}} float 0x3FB9999980000000
+// CHECK: @C2_ru = {{.*}} float 0x3FB99999A0000000
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+float C3_rd = CONSTANT_0_1_RM(0.1F, FE_DOWNWARD);
+float C3_ru = CONSTANT_0_1_RM(0.1F, FE_UPWARD);
+// CHECK: @C3_rd = {{.*}} float 0x3FB9999980000000
+// CHECK: @C3_ru = {{.*}} float 0x3FB99999A0000000
+
+// Check literals in template instantiations.
+
+#pragma STDC FENV_ROUND FE_DYNAMIC
+
+template<typename T, T C>
+constexpr T foo() {
+  return C;
+}
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+float var_d = foo<float, 0.1F>();
+// CHECK: @var_d = {{.*}} float 0x3FB9999980000000
+
+#pragma STDC FENV_ROUND FE_UPWARD
+float var_u = foo<float, 0.1F>();
+// CHECK: @var_u = {{.*}} float 0x3FB99999A0000000
+
+#pragma STDC FENV_ROUND FE_DYNAMIC
+
+template<typename T, T f> void foo2() {
+  T Val = f;
+}
+
+void func_01() {
+  #pragma STDC FENV_ROUND FE_DOWNWARD
+  foo2<float, 0.1f>();
+}
+
+void func_02() {
+  #pragma STDC FENV_ROUND FE_UPWARD
+  foo2<float, 0.1f>();
+}
+
+// CHECK-LABEL: define {{.*}} void @_Z4foo2IfTnT_Lf3dccccccEEvv()
+// CHECK:         store float 0x3FB9999980000000, ptr
+
+// CHECK-LABEL: define {{.*}} void @_Z4foo2IfTnT_Lf3dcccccdEEvv()
+// CHECK:         store float 0x3FB99999A0000000, ptr
+
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+template <int C>
+float tfunc_01() {
+  return 0.1F;  // Must be 0x3FB9999980000000 in all instantiations.
+}
+template float tfunc_01<0>();
+// CHECK-LABEL: define {{.*}} float @_Z8tfunc_01ILi0EEfv()
+// CHECK:         ret float 0x3FB9999980000000
+
+#pragma STDC FENV_ROUND FE_UPWARD
+template float tfunc_01<1>();
+// CHECK-LABEL: define {{.*}} float @_Z8tfunc_01ILi1EEfv()
+// CHECK:         ret float 0x3FB9999980000000
+
+template<> float tfunc_01<2>() {
+  return 0.1F;
+}
+// CHECK-LABEL: define {{.*}} float @_Z8tfunc_01ILi2EEfv()
+// CHECK:         ret float 0x3FB99999A0000000


        


More information about the cfe-commits mailing list