Skip to content

Commit 3360e6c

Browse files
committed
[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.
1 parent 705fcd4 commit 3360e6c

File tree

5 files changed

+175
-0
lines changed

5 files changed

+175
-0
lines changed

clang/lib/Frontend/InitPreprocessor.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,59 @@ void InitializeOpenCLFeatureTestMacros(const TargetInfo &TI,
768768
Builder.defineMacro("__opencl_c_int64");
769769
}
770770

771+
std::string ConstructFixedPointLiteral(llvm::APFixedPoint Val,
772+
llvm::StringRef Suffix) {
773+
if (Val.isSigned() && Val == llvm::APFixedPoint::getMin(Val.getSemantics())) {
774+
// When representing the min value of a signed fixed point type in source
775+
// code, we cannot simply write `-<lowest value>`. For example, the min
776+
// value of a `short _Fract` cannot be written as `-1.0hr`. This is because
777+
// the parser will read this (and really any negative numerical literal) as
778+
// a UnaryOperator that owns a FixedPointLiteral with a positive value
779+
// rather than just a FixedPointLiteral with a negative value. Compiling
780+
// `-1.0hr` results in an overflow to the maximal value of that fixed point
781+
// type. The correct way to represent a signed min value is to instead split
782+
// it into two halves, like `(-0.5hr-0.5hr)` which is what the standard
783+
// defines SFRACT_MIN as.
784+
std::string Literal;
785+
std::string HalfStr = ConstructFixedPointLiteral(Val.shr(1), Suffix);
786+
Literal.push_back('(');
787+
Literal += HalfStr;
788+
Literal += HalfStr;
789+
Literal.push_back(')');
790+
return Literal;
791+
}
792+
793+
std::string Str(Val.toString());
794+
Str += Suffix;
795+
return Str;
796+
}
797+
798+
void DefineFixedPointMacros(const TargetInfo &TI, MacroBuilder &Builder,
799+
llvm::StringRef TypeName, llvm::StringRef Suffix,
800+
unsigned Width, unsigned Scale, bool Signed) {
801+
// Saturation doesn't affect the size or scale of a fixed point type, so we
802+
// don't need it here.
803+
llvm::FixedPointSemantics FXSema(
804+
Width, Scale, Signed, /*IsSaturated=*/false,
805+
!Signed && TI.doUnsignedFixedPointTypesHavePadding());
806+
llvm::SmallString<32> MacroPrefix("__");
807+
MacroPrefix += TypeName;
808+
Builder.defineMacro(MacroPrefix + "_EPSILON__",
809+
ConstructFixedPointLiteral(
810+
llvm::APFixedPoint::getEpsilon(FXSema), Suffix));
811+
Builder.defineMacro(MacroPrefix + "_FBIT__", Twine(Scale));
812+
Builder.defineMacro(
813+
MacroPrefix + "_MAX__",
814+
ConstructFixedPointLiteral(llvm::APFixedPoint::getMax(FXSema), Suffix));
815+
816+
// N1169 doesn't specify MIN macros for unsigned types since they're all just
817+
// zero.
818+
if (Signed)
819+
Builder.defineMacro(
820+
MacroPrefix + "_MIN__",
821+
ConstructFixedPointLiteral(llvm::APFixedPoint::getMin(FXSema), Suffix));
822+
}
823+
771824
static void InitializePredefinedMacros(const TargetInfo &TI,
772825
const LangOptions &LangOpts,
773826
const FrontendOptions &FEOpts,
@@ -1097,6 +1150,47 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
10971150
TI.getTypeWidth(TI.getIntMaxType()) &&
10981151
"uintmax_t and intmax_t have different widths?");
10991152

1153+
if (LangOpts.FixedPoint) {
1154+
// Each unsigned type has the same width as their signed type.
1155+
DefineFixedPointMacros(TI, Builder, "SFRACT", "hr", TI.getShortFractWidth(),
1156+
TI.getShortFractScale(), /*Signed=*/true);
1157+
DefineFixedPointMacros(TI, Builder, "USFRACT", "uhr",
1158+
TI.getShortFractWidth(),
1159+
TI.getUnsignedShortFractScale(), /*Signed=*/false);
1160+
DefineFixedPointMacros(TI, Builder, "FRACT", "r", TI.getFractWidth(),
1161+
TI.getFractScale(), /*Signed=*/true);
1162+
DefineFixedPointMacros(TI, Builder, "UFRACT", "ur", TI.getFractWidth(),
1163+
TI.getUnsignedFractScale(), /*Signed=*/false);
1164+
DefineFixedPointMacros(TI, Builder, "LFRACT", "lr", TI.getLongFractWidth(),
1165+
TI.getLongFractScale(), /*Signed=*/true);
1166+
DefineFixedPointMacros(TI, Builder, "ULFRACT", "ulr",
1167+
TI.getLongFractWidth(),
1168+
TI.getUnsignedLongFractScale(), /*Signed=*/false);
1169+
DefineFixedPointMacros(TI, Builder, "SACCUM", "hk", TI.getShortAccumWidth(),
1170+
TI.getShortAccumScale(), /*Signed=*/true);
1171+
DefineFixedPointMacros(TI, Builder, "USACCUM", "uhk",
1172+
TI.getShortAccumWidth(),
1173+
TI.getUnsignedShortAccumScale(), /*Signed=*/false);
1174+
DefineFixedPointMacros(TI, Builder, "ACCUM", "k", TI.getAccumWidth(),
1175+
TI.getAccumScale(), /*Signed=*/true);
1176+
DefineFixedPointMacros(TI, Builder, "UACCUM", "uk", TI.getAccumWidth(),
1177+
TI.getUnsignedAccumScale(), /*Signed=*/false);
1178+
DefineFixedPointMacros(TI, Builder, "LACCUM", "lk", TI.getLongAccumWidth(),
1179+
TI.getLongAccumScale(), /*Signed=*/true);
1180+
DefineFixedPointMacros(TI, Builder, "ULACCUM", "ulk",
1181+
TI.getLongAccumWidth(),
1182+
TI.getUnsignedLongAccumScale(), /*Signed=*/false);
1183+
1184+
Builder.defineMacro("__SACCUM_IBIT__", Twine(TI.getShortAccumIBits()));
1185+
Builder.defineMacro("__USACCUM_IBIT__",
1186+
Twine(TI.getUnsignedShortAccumIBits()));
1187+
Builder.defineMacro("__ACCUM_IBIT__", Twine(TI.getAccumIBits()));
1188+
Builder.defineMacro("__UACCUM_IBIT__", Twine(TI.getUnsignedAccumIBits()));
1189+
Builder.defineMacro("__LACCUM_IBIT__", Twine(TI.getLongAccumIBits()));
1190+
Builder.defineMacro("__ULACCUM_IBIT__",
1191+
Twine(TI.getUnsignedLongAccumIBits()));
1192+
}
1193+
11001194
if (TI.hasFloat16Type())
11011195
DefineFloatMacros(Builder, "FLT16", &TI.getHalfFormat(), "F16");
11021196
DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F");

clang/test/Preprocessor/fixed-point.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/// Assert the fixed point precision macros according to N1169 7.18a.3 are
2+
/// defined when -ffixed-point is provided.
3+
4+
// RUN: %clang_cc1 -triple=x86_64 -E -dM -ffixed-point -x c < /dev/null | FileCheck -match-full-lines %s
5+
// RUN: %clang_cc1 -triple=x86_64 -E -dM -ffixed-point -x c++ < /dev/null | FileCheck -match-full-lines %s
6+
7+
/// These are the implementation-defined values for x86_64.
8+
// CHECK-DAG:#define __SFRACT_EPSILON__ 0.0078125hr
9+
// CHECK-DAG:#define __SFRACT_FBIT__ 7
10+
// CHECK-DAG:#define __SFRACT_MAX__ 0.9921875hr
11+
// CHECK-DAG:#define __SFRACT_MIN__ (-0.5hr-0.5hr)
12+
13+
// CHECK-DAG:#define __USFRACT_EPSILON__ 0.00390625uhr
14+
// CHECK-DAG:#define __USFRACT_FBIT__ 8
15+
// CHECK-DAG:#define __USFRACT_MAX__ 0.99609375uhr
16+
17+
// CHECK-DAG:#define __FRACT_EPSILON__ 0.000030517578125r
18+
// CHECK-DAG:#define __FRACT_FBIT__ 15
19+
// CHECK-DAG:#define __FRACT_MAX__ 0.999969482421875r
20+
// CHECK-DAG:#define __FRACT_MIN__ (-0.5r-0.5r)
21+
22+
// CHECK-DAG:#define __UFRACT_EPSILON__ 0.0000152587890625ur
23+
// CHECK-DAG:#define __UFRACT_FBIT__ 16
24+
// CHECK-DAG:#define __UFRACT_MAX__ 0.9999847412109375ur
25+
26+
// CHECK-DAG:#define __LFRACT_EPSILON__ 0.0000000004656612873077392578125lr
27+
// CHECK-DAG:#define __LFRACT_FBIT__ 31
28+
// CHECK-DAG:#define __LFRACT_MAX__ 0.9999999995343387126922607421875lr
29+
// CHECK-DAG:#define __LFRACT_MIN__ (-0.5lr-0.5lr)
30+
31+
// CHECK-DAG:#define __ULFRACT_EPSILON__ 0.00000000023283064365386962890625ulr
32+
// CHECK-DAG:#define __ULFRACT_FBIT__ 32
33+
// CHECK-DAG:#define __ULFRACT_MAX__ 0.99999999976716935634613037109375ulr
34+
35+
// CHECK-DAG:#define __SACCUM_EPSILON__ 0.0078125hk
36+
// CHECK-DAG:#define __SACCUM_FBIT__ 7
37+
// CHECK-DAG:#define __SACCUM_MAX__ 255.9921875hk
38+
// CHECK-DAG:#define __SACCUM_MIN__ (-128.0hk-128.0hk)
39+
40+
// CHECK-DAG:#define __USACCUM_EPSILON__ 0.00390625uhk
41+
// CHECK-DAG:#define __USACCUM_FBIT__ 8
42+
// CHECK-DAG:#define __USACCUM_MAX__ 255.99609375uhk
43+
44+
// CHECK-DAG:#define __ACCUM_EPSILON__ 0.000030517578125k
45+
// CHECK-DAG:#define __ACCUM_FBIT__ 15
46+
// CHECK-DAG:#define __ACCUM_MAX__ 65535.999969482421875k
47+
// CHECK-DAG:#define __ACCUM_MIN__ (-32768.0k-32768.0k)
48+
49+
// CHECK-DAG:#define __UACCUM_EPSILON__ 0.0000152587890625uk
50+
// CHECK-DAG:#define __UACCUM_FBIT__ 16
51+
// CHECK-DAG:#define __UACCUM_MAX__ 65535.9999847412109375uk
52+
53+
// CHECK-DAG:#define __LACCUM_EPSILON__ 0.0000000004656612873077392578125lk
54+
// CHECK-DAG:#define __LACCUM_FBIT__ 31
55+
// CHECK-DAG:#define __LACCUM_MAX__ 4294967295.9999999995343387126922607421875lk
56+
// CHECK-DAG:#define __LACCUM_MIN__ (-2147483648.0lk-2147483648.0lk)
57+
58+
// CHECK-DAG:#define __ULACCUM_EPSILON__ 0.00000000023283064365386962890625ulk
59+
// CHECK-DAG:#define __ULACCUM_FBIT__ 32
60+
// CHECK-DAG:#define __ULACCUM_MAX__ 4294967295.99999999976716935634613037109375ulk
61+
62+
// CHECK-DAG:#define __SACCUM_IBIT__ 8
63+
// CHECK-DAG:#define __USACCUM_IBIT__ 8
64+
// CHECK-DAG:#define __ACCUM_IBIT__ 16
65+
// CHECK-DAG:#define __UACCUM_IBIT__ 16
66+
// CHECK-DAG:#define __LACCUM_IBIT__ 32
67+
// CHECK-DAG:#define __ULACCUM_IBIT__ 32
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/// Assert the fixed point precision macros according to N1169 7.18a.3 are not
2+
/// defined when -ffixed-point is not provided.
3+
4+
// RUN: %clang_cc1 -triple=x86_64 -E -dM -x c < /dev/null | FileCheck -match-full-lines %s
5+
// RUN: %clang_cc1 -triple=x86_64 -E -dM -x c++ < /dev/null | FileCheck -match-full-lines %s
6+
7+
// CHECK-NOT:#define __SFRACT_FBIT__ 7

llvm/include/llvm/ADT/APFixedPoint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ class APFixedPoint {
260260

261261
static APFixedPoint getMax(const FixedPointSemantics &Sema);
262262
static APFixedPoint getMin(const FixedPointSemantics &Sema);
263+
static APFixedPoint getEpsilon(const FixedPointSemantics &Sema);
263264

264265
/// Given a floating point semantic, return the next floating point semantic
265266
/// with a larger exponent and larger or equal mantissa.

llvm/lib/Support/APFixedPoint.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
129129
return APFixedPoint(Val, Sema);
130130
}
131131

132+
APFixedPoint APFixedPoint::getEpsilon(const FixedPointSemantics &Sema) {
133+
APSInt Val(Sema.getWidth(), !Sema.isSigned());
134+
Val.setBit(/*BitPosition=*/0);
135+
return APFixedPoint(Val, Sema);
136+
}
137+
132138
bool FixedPointSemantics::fitsInFloatSemantics(
133139
const fltSemantics &FloatSema) const {
134140
// A fixed point semantic fits in a floating point semantic if the maximum

0 commit comments

Comments
 (0)