[clang] [llvm] [clang] Add fixed point precision macros (PR #81207)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 8 16:14:28 PST 2024
https://github.com/PiJoules created https://github.com/llvm/llvm-project/pull/81207
This defines the builtin macros specified in `7.18a.3 Precision macros` of N1169. These are the `__*__` versions of them and the formal definitions in stdfix.h can use them.
>From 23f6ff492970eed134af025307d0c6dce3857205 Mon Sep 17 00:00:00 2001
From: Leonard Chan <leonardchan at google.com>
Date: Thu, 8 Feb 2024 16:12:35 -0800
Subject: [PATCH] [clang] Add fixed point precision macros
This defines the builtin macros specified in `7.18a.3 Precision macros`
of N1169. These are the `__*__` versions of them and the formal
definitions in stdfix.h can use them.
---
clang/lib/Frontend/InitPreprocessor.cpp | 93 ++++++++++++++++++++++++
clang/test/Preprocessor/fixed-point.c | 67 +++++++++++++++++
clang/test/Preprocessor/no-fixed-point.c | 7 ++
llvm/include/llvm/ADT/APFixedPoint.h | 1 +
llvm/lib/Support/APFixedPoint.cpp | 6 ++
5 files changed, 174 insertions(+)
create mode 100644 clang/test/Preprocessor/fixed-point.c
create mode 100644 clang/test/Preprocessor/no-fixed-point.c
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 877e205e2e9bfa..7a136fb6bdcdf9 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -768,6 +768,58 @@ void InitializeOpenCLFeatureTestMacros(const TargetInfo &TI,
Builder.defineMacro("__opencl_c_int64");
}
+std::string ConstructFixedPointLiteral(llvm::APFixedPoint Val,
+ llvm::StringRef Suffix) {
+ if (Val.isSigned() && Val == llvm::APFixedPoint::getMin(Val.getSemantics())) {
+ // When representing the min value of a signed fixed point type in source
+ // code, we cannot simply write `-<lowest value>`. For example, the min
+ // value of a `short _Fract` cannot be written as `-1.0hr`. This is because
+ // the parser will read this (and really any negative numerical literal) as
+ // a UnaryOperator that owns a FixedPointLiteral with a positive value
+ // rather than just a FixedPointLiteral with a negative value. Compiling
+ // `-1.0hr` results in an overflow to the maximal value of that fixed point
+ // type. The correct way to represent a signed min value is to instead split
+ // it into two halves, like `(-0.5hr-0.5hr)` which is what the standard
+ // defines SFRACT_MIN as.
+ std::string Literal;
+ std::string HalfStr = ConstructFixedPointLiteral(Val.shr(1), Suffix);
+ Literal.push_back('(');
+ Literal += HalfStr;
+ Literal += HalfStr;
+ Literal.push_back(')');
+ return Literal;
+ }
+
+ std::string Str(Val.toString());
+ Str += Suffix;
+ return Str;
+}
+
+void DefineFixedPointMacros(const TargetInfo &TI, MacroBuilder &Builder,
+ llvm::StringRef TypeName, llvm::StringRef Suffix,
+ unsigned Width, unsigned Scale, bool Signed) {
+ // Saturation doesn't affect the size or scale of a fixed point type, so we
+ // don't need it here.
+ llvm::FixedPointSemantics FXSema(Width, Scale, Signed, /*IsSaturated=*/false,
+ TI.doUnsignedFixedPointTypesHavePadding());
+ llvm::SmallString<32> MacroPrefix("__");
+ MacroPrefix += TypeName;
+ Builder.defineMacro(MacroPrefix + "_EPSILON__",
+ ConstructFixedPointLiteral(
+ llvm::APFixedPoint::getEpsilon(FXSema), Suffix));
+ Builder.defineMacro(MacroPrefix + "_FBIT__", Twine(Scale));
+ Builder.defineMacro(
+ MacroPrefix + "_MAX__",
+ ConstructFixedPointLiteral(llvm::APFixedPoint::getMax(FXSema), Suffix));
+
+ // N1169 doesn't specify MIN macros for unsigned types since they're all just
+ // zero.
+ if (Signed)
+ Builder.defineMacro(
+ MacroPrefix + "_MIN__",
+ ConstructFixedPointLiteral(llvm::APFixedPoint::getMin(FXSema), Suffix));
+}
+
static void InitializePredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
@@ -1097,6 +1149,47 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
TI.getTypeWidth(TI.getIntMaxType()) &&
"uintmax_t and intmax_t have different widths?");
+ if (LangOpts.FixedPoint) {
+ // Each unsigned type has the same width as their signed type.
+ DefineFixedPointMacros(TI, Builder, "SFRACT", "hr", TI.getShortFractWidth(),
+ TI.getShortFractScale(), /*Signed=*/true);
+ DefineFixedPointMacros(TI, Builder, "USFRACT", "uhr",
+ TI.getShortFractWidth(),
+ TI.getUnsignedShortFractScale(), /*Signed=*/false);
+ DefineFixedPointMacros(TI, Builder, "FRACT", "r", TI.getFractWidth(),
+ TI.getFractScale(), /*Signed=*/true);
+ DefineFixedPointMacros(TI, Builder, "UFRACT", "ur", TI.getFractWidth(),
+ TI.getUnsignedFractScale(), /*Signed=*/false);
+ DefineFixedPointMacros(TI, Builder, "LFRACT", "lr", TI.getLongFractWidth(),
+ TI.getLongFractScale(), /*Signed=*/true);
+ DefineFixedPointMacros(TI, Builder, "ULFRACT", "ulr",
+ TI.getLongFractWidth(),
+ TI.getUnsignedLongFractScale(), /*Signed=*/false);
+ DefineFixedPointMacros(TI, Builder, "SACCUM", "hk", TI.getShortAccumWidth(),
+ TI.getShortAccumScale(), /*Signed=*/true);
+ DefineFixedPointMacros(TI, Builder, "USACCUM", "uhk",
+ TI.getShortAccumWidth(),
+ TI.getUnsignedShortAccumScale(), /*Signed=*/false);
+ DefineFixedPointMacros(TI, Builder, "ACCUM", "k", TI.getAccumWidth(),
+ TI.getAccumScale(), /*Signed=*/true);
+ DefineFixedPointMacros(TI, Builder, "UACCUM", "uk", TI.getAccumWidth(),
+ TI.getUnsignedAccumScale(), /*Signed=*/false);
+ DefineFixedPointMacros(TI, Builder, "LACCUM", "lk", TI.getLongAccumWidth(),
+ TI.getLongAccumScale(), /*Signed=*/true);
+ DefineFixedPointMacros(TI, Builder, "ULACCUM", "ulk",
+ TI.getLongAccumWidth(),
+ TI.getUnsignedLongAccumScale(), /*Signed=*/false);
+
+ Builder.defineMacro("__SACCUM_IBIT__", Twine(TI.getShortAccumIBits()));
+ Builder.defineMacro("__USACCUM_IBIT__",
+ Twine(TI.getUnsignedShortAccumIBits()));
+ Builder.defineMacro("__ACCUM_IBIT__", Twine(TI.getAccumIBits()));
+ Builder.defineMacro("__UACCUM_IBIT__", Twine(TI.getUnsignedAccumIBits()));
+ Builder.defineMacro("__LACCUM_IBIT__", Twine(TI.getLongAccumIBits()));
+ Builder.defineMacro("__ULACCUM_IBIT__",
+ Twine(TI.getUnsignedLongAccumIBits()));
+ }
+
if (TI.hasFloat16Type())
DefineFloatMacros(Builder, "FLT16", &TI.getHalfFormat(), "F16");
DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F");
diff --git a/clang/test/Preprocessor/fixed-point.c b/clang/test/Preprocessor/fixed-point.c
new file mode 100644
index 00000000000000..fab05bb7e4d862
--- /dev/null
+++ b/clang/test/Preprocessor/fixed-point.c
@@ -0,0 +1,67 @@
+/// Assert the fixed point precision macros according to N1169 7.18a.3 are
+/// defined when -ffixed-point is provided.
+
+// RUN: %clang_cc1 -triple=x86_64 -E -dM -ffixed-point -x c < /dev/null | FileCheck -match-full-lines %s
+// RUN: %clang_cc1 -triple=x86_64 -E -dM -ffixed-point -x c++ < /dev/null | FileCheck -match-full-lines %s
+
+/// These are the implementation-defined values for x86_64.
+// CHECK-DAG:#define __SFRACT_EPSILON__ 0.0078125hr
+// CHECK-DAG:#define __SFRACT_FBIT__ 7
+// CHECK-DAG:#define __SFRACT_MAX__ 0.9921875hr
+// CHECK-DAG:#define __SFRACT_MIN__ (-0.5hr-0.5hr)
+
+// CHECK-DAG:#define __USFRACT_EPSILON__ 0.00390625uhr
+// CHECK-DAG:#define __USFRACT_FBIT__ 8
+// CHECK-DAG:#define __USFRACT_MAX__ 0.99609375uhr
+
+// CHECK-DAG:#define __FRACT_EPSILON__ 0.000030517578125r
+// CHECK-DAG:#define __FRACT_FBIT__ 15
+// CHECK-DAG:#define __FRACT_MAX__ 0.999969482421875r
+// CHECK-DAG:#define __FRACT_MIN__ (-0.5r-0.5r)
+
+// CHECK-DAG:#define __UFRACT_EPSILON__ 0.0000152587890625ur
+// CHECK-DAG:#define __UFRACT_FBIT__ 16
+// CHECK-DAG:#define __UFRACT_MAX__ 0.9999847412109375ur
+
+// CHECK-DAG:#define __LFRACT_EPSILON__ 0.0000000004656612873077392578125lr
+// CHECK-DAG:#define __LFRACT_FBIT__ 31
+// CHECK-DAG:#define __LFRACT_MAX__ 0.9999999995343387126922607421875lr
+// CHECK-DAG:#define __LFRACT_MIN__ (-0.5lr-0.5lr)
+
+// CHECK-DAG:#define __ULFRACT_EPSILON__ 0.00000000023283064365386962890625ulr
+// CHECK-DAG:#define __ULFRACT_FBIT__ 32
+// CHECK-DAG:#define __ULFRACT_MAX__ 0.99999999976716935634613037109375ulr
+
+// CHECK-DAG:#define __SACCUM_EPSILON__ 0.0078125hk
+// CHECK-DAG:#define __SACCUM_FBIT__ 7
+// CHECK-DAG:#define __SACCUM_MAX__ 255.9921875hk
+// CHECK-DAG:#define __SACCUM_MIN__ (-128.0hk-128.0hk)
+
+// CHECK-DAG:#define __USACCUM_EPSILON__ 0.00390625uhk
+// CHECK-DAG:#define __USACCUM_FBIT__ 8
+// CHECK-DAG:#define __USACCUM_MAX__ 255.99609375uhk
+
+// CHECK-DAG:#define __ACCUM_EPSILON__ 0.000030517578125k
+// CHECK-DAG:#define __ACCUM_FBIT__ 15
+// CHECK-DAG:#define __ACCUM_MAX__ 65535.999969482421875k
+// CHECK-DAG:#define __ACCUM_MIN__ (-32768.0k-32768.0k)
+
+// CHECK-DAG:#define __UACCUM_EPSILON__ 0.0000152587890625uk
+// CHECK-DAG:#define __UACCUM_FBIT__ 16
+// CHECK-DAG:#define __UACCUM_MAX__ 65535.9999847412109375uk
+
+// CHECK-DAG:#define __LACCUM_EPSILON__ 0.0000000004656612873077392578125lk
+// CHECK-DAG:#define __LACCUM_FBIT__ 31
+// CHECK-DAG:#define __LACCUM_MAX__ 4294967295.9999999995343387126922607421875lk
+// CHECK-DAG:#define __LACCUM_MIN__ (-2147483648.0lk-2147483648.0lk)
+
+// CHECK-DAG:#define __ULACCUM_EPSILON__ 0.00000000023283064365386962890625ulk
+// CHECK-DAG:#define __ULACCUM_FBIT__ 32
+// CHECK-DAG:#define __ULACCUM_MAX__ 4294967295.99999999976716935634613037109375ulk
+
+// CHECK-DAG:#define __SACCUM_IBIT__ 8
+// CHECK-DAG:#define __USACCUM_IBIT__ 8
+// CHECK-DAG:#define __ACCUM_IBIT__ 16
+// CHECK-DAG:#define __UACCUM_IBIT__ 16
+// CHECK-DAG:#define __LACCUM_IBIT__ 32
+// CHECK-DAG:#define __ULACCUM_IBIT__ 32
diff --git a/clang/test/Preprocessor/no-fixed-point.c b/clang/test/Preprocessor/no-fixed-point.c
new file mode 100644
index 00000000000000..e10a4b6c9e4eee
--- /dev/null
+++ b/clang/test/Preprocessor/no-fixed-point.c
@@ -0,0 +1,7 @@
+/// Assert the fixed point precision macros according to N1169 7.18a.3 are not
+/// defined when -ffixed-point is not provided.
+
+// RUN: %clang_cc1 -triple=x86_64 -E -dM -x c < /dev/null | FileCheck -match-full-lines %s
+// RUN: %clang_cc1 -triple=x86_64 -E -dM -x c++ < /dev/null | FileCheck -match-full-lines %s
+
+// CHECK-NOT:#define __SFRACT_FBIT__ 7
diff --git a/llvm/include/llvm/ADT/APFixedPoint.h b/llvm/include/llvm/ADT/APFixedPoint.h
index b0c510865f444e..0c014e76aa7126 100644
--- a/llvm/include/llvm/ADT/APFixedPoint.h
+++ b/llvm/include/llvm/ADT/APFixedPoint.h
@@ -260,6 +260,7 @@ class APFixedPoint {
static APFixedPoint getMax(const FixedPointSemantics &Sema);
static APFixedPoint getMin(const FixedPointSemantics &Sema);
+ static APFixedPoint getEpsilon(const FixedPointSemantics &Sema);
/// Given a floating point semantic, return the next floating point semantic
/// with a larger exponent and larger or equal mantissa.
diff --git a/llvm/lib/Support/APFixedPoint.cpp b/llvm/lib/Support/APFixedPoint.cpp
index 3eea01bc98093a..249c4f1e2153da 100644
--- a/llvm/lib/Support/APFixedPoint.cpp
+++ b/llvm/lib/Support/APFixedPoint.cpp
@@ -129,6 +129,12 @@ APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
return APFixedPoint(Val, Sema);
}
+APFixedPoint APFixedPoint::getEpsilon(const FixedPointSemantics &Sema) {
+ APSInt Val(Sema.getWidth(), !Sema.isSigned());
+ Val.setBit(/*BitPosition=*/0);
+ return APFixedPoint(Val, Sema);
+}
+
bool FixedPointSemantics::fitsInFloatSemantics(
const fltSemantics &FloatSema) const {
// A fixed point semantic fits in a floating point semantic if the maximum
More information about the cfe-commits
mailing list