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

Serge Pavlov via cfe-commits cfe-commits at lists.llvm.org
Fri May 3 10:50:43 PDT 2024


https://github.com/spavloff updated https://github.com/llvm/llvm-project/pull/90877

>From 5d906b537636ca0d8706a8a888dd78edfbec684f Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Thu, 2 May 2024 22:28:05 +0700
Subject: [PATCH 1/7] [clang] Use constant rounding mode for floating literals

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.
---
 clang/include/clang/Lex/LiteralSupport.h | 10 ++++------
 clang/lib/Lex/LiteralSupport.cpp         |  6 +++---
 clang/lib/Sema/SemaExpr.cpp              |  3 ++-
 clang/test/AST/const-fpfeatures.c        |  6 ++++++
 4 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h
index 2ed42d1c5f9aae9..705021fcfa5b11b 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 9c0cbea5052cb23..3df0391bdda772f 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 0cca02c338954a1..db96c8692f2516f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3858,7 +3858,8 @@ static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
   using llvm::APFloat;
   APFloat Val(Format);
 
-  APFloat::opStatus result = Literal.GetFloatValue(Val);
+  APFloat::opStatus result =
+      Literal.GetFloatValue(Val, S.CurFPFeatures.getRoundingMode());
 
   // 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 6600ea27405d9c8..247245c776fed17 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 0x3FB9999980000000
+
 
 #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 0x3FB99999A0000000

>From a6fad25517b283c4b282324595d1e84f99717e16 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Fri, 3 May 2024 13:45:36 +0700
Subject: [PATCH 2/7] Fix typo

---
 clang/test/AST/const-fpfeatures.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/AST/const-fpfeatures.c b/clang/test/AST/const-fpfeatures.c
index 247245c776fed17..276d46b70c21d93 100644
--- a/clang/test/AST/const-fpfeatures.c
+++ b/clang/test/AST/const-fpfeatures.c
@@ -20,7 +20,7 @@ float _Complex C1u = C0;
 // CHECK: @C1u = {{.*}} { float, float } { float 0x3FF0000020000000, float 0x3FF0000020000000 }
 
 float FLu = 0.1F;
-// CHECK: @FLu = {{.*}} float 0x3FB9999980000000
+// CHECK: @FLu = {{.*}} float 0x3FB99999A0000000
 
 
 #pragma STDC FENV_ROUND FE_DOWNWARD
@@ -40,4 +40,4 @@ float _Complex C1d = C0;
 // CHECK: @C1d = {{.*}} { float, float } { float 1.000000e+00, float 1.000000e+00 }
 
 float FLd = 0.1F;
-// CHECK: @FLd = {{.*}} float 0x3FB99999A0000000
+// CHECK: @FLd = {{.*}} float 0x3FB9999980000000

>From f2e04141fc76b2ddf7e4481ebecd5392f1653843 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Fri, 3 May 2024 19:08:49 +0700
Subject: [PATCH 3/7] Add test for NTTP

---
 clang/test/AST/const-fpfeatures.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/clang/test/AST/const-fpfeatures.cpp b/clang/test/AST/const-fpfeatures.cpp
index 9c807b34625f3a0..c5739359b10e0a8 100644
--- a/clang/test/AST/const-fpfeatures.cpp
+++ b/clang/test/AST/const-fpfeatures.cpp
@@ -79,3 +79,16 @@ float V7 = []() -> float {
   0x0.000001p0F);
 }();
 // CHECK: @V7 = {{.*}} float 1.000000e+00
+
+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 }

>From cf6ff55ad4a45875a821b3ac82c22bb7917b4d67 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Fri, 3 May 2024 20:04:13 +0700
Subject: [PATCH 4/7] Replace dynamic rounding mode with NearestTiesToEven

---
 clang/lib/Sema/SemaExpr.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index db96c8692f2516f..da107a684446c9f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3858,8 +3858,11 @@ static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
   using llvm::APFloat;
   APFloat Val(Format);
 
+  llvm::RoundingMode RM = S.CurFPFeatures.getRoundingMode();
+  if (RM == llvm::RoundingMode::Dynamic)
+    RM = llvm::RoundingMode::NearestTiesToEven;
   APFloat::opStatus result =
-      Literal.GetFloatValue(Val, S.CurFPFeatures.getRoundingMode());
+      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).

>From aeb6074444513587924106081213335f73ba6eb0 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Fri, 3 May 2024 22:16:54 +0700
Subject: [PATCH 5/7] Add additional test for float literal as NTTP

---
 clang/test/AST/const-fpfeatures.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/clang/test/AST/const-fpfeatures.cpp b/clang/test/AST/const-fpfeatures.cpp
index c5739359b10e0a8..df8856de3f1ec3e 100644
--- a/clang/test/AST/const-fpfeatures.cpp
+++ b/clang/test/AST/const-fpfeatures.cpp
@@ -92,3 +92,16 @@ L<0.1F> val_d;
 #pragma STDC FENV_ROUND FE_UPWARD
 L<0.1F> val_u;
 // CHECK: @val_u = {{.*}} { float 0x3FB99999A0000000 }
+
+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

>From ed25d8a3df2d27b63481cf9468f6a2a807defbf0 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Fri, 3 May 2024 22:50:25 +0700
Subject: [PATCH 6/7] Fix clang-format error

---
 clang/lib/Sema/SemaExpr.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index da107a684446c9f..a344d1281e60afe 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3861,8 +3861,7 @@ static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
   llvm::RoundingMode RM = S.CurFPFeatures.getRoundingMode();
   if (RM == llvm::RoundingMode::Dynamic)
     RM = llvm::RoundingMode::NearestTiesToEven;
-  APFloat::opStatus result =
-      Literal.GetFloatValue(Val, RM);
+  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).

>From da2795c2a84a96f4942e3464f30de8ae0d1ddd26 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Sat, 4 May 2024 00:49:59 +0700
Subject: [PATCH 7/7] Add test for template instatiations

---
 clang/test/AST/const-fpfeatures.cpp | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/clang/test/AST/const-fpfeatures.cpp b/clang/test/AST/const-fpfeatures.cpp
index df8856de3f1ec3e..4065452306668b3 100644
--- a/clang/test/AST/const-fpfeatures.cpp
+++ b/clang/test/AST/const-fpfeatures.cpp
@@ -80,6 +80,8 @@ float V7 = []() -> float {
 }();
 // CHECK: @V7 = {{.*}} float 1.000000e+00
 
+#pragma STDC FENV_ROUND FE_DYNAMIC
+
 template<float V> struct L {
   constexpr L() : value(V) {}
   float value;
@@ -93,6 +95,8 @@ L<0.1F> val_d;
 L<0.1F> val_u;
 // CHECK: @val_u = {{.*}} { float 0x3FB99999A0000000 }
 
+#pragma STDC FENV_ROUND FE_DYNAMIC
+
 template<typename T, T C>
 constexpr T foo() {
   return C;
@@ -105,3 +109,25 @@ float var_d = foo<float, 0.1F>();
 #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



More information about the cfe-commits mailing list