[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 07:57:14 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/4] [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 2ed42d1c5f9aae..705021fcfa5b11 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 9c0cbea5052cb2..3df0391bdda772 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 0cca02c338954a..db96c8692f2516 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 6600ea27405d9c..247245c776fed1 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/4] 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 247245c776fed1..276d46b70c21d9 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/4] 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 9c807b34625f3a..c5739359b10e0a 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/4] 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 db96c8692f2516..da107a684446c9 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).
More information about the cfe-commits
mailing list