Skip to content

Commit 2c69eb0

Browse files
committed
[Clang][C++23] Implement core language changes from P1467R9 extended
floating-point types and standard names. This commit implements Core language changes based on P1467R9 Extended floating-point types and standard names. As per the proposal's definition the following two types are marked as extended floating point: Float16 (aka _Float16) and Bfloat16 (aka decltype (0.0bf16) or __bf16). Future work can extend this to support other floating-point types such as Float32, Float64, and Float128. RFC: https://discourse.llvm.org/t/rfc-c-23-p1467r9-extended-floating-point-types-and-standard-names/70033 Differential Revision: https://reviews.llvm.org/D149573
1 parent 78f0447 commit 2c69eb0

File tree

20 files changed

+1507
-46
lines changed

20 files changed

+1507
-46
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,11 @@ C++ Language Changes
248248
- The builtin type alias ``__builtin_common_type`` has been added to improve the
249249
performance of ``std::common_type``.
250250

251+
- Implemented `P1467R9: Extended floating-point types and standard names <https://wg21.link/P1467R9>`_. Enables
252+
extended floating-point types beyond the three standard ones, establishing rules for their interactions and
253+
conversions with each other and other types, while ensuring no alteration in the behavior of existing
254+
standard types. The current implementation enables support for `std::float16_t` and `std::bfloat16_t` types.
255+
251256
C++2c Feature Support
252257
^^^^^^^^^^^^^^^^^^^^^
253258

clang/include/clang/AST/ASTContext.h

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ template <typename T, unsigned N> class SmallPtrSet;
5555

5656
namespace clang {
5757

58+
// Conversion ranks introduced in C++23 6.8.6p2 [conv.rank]
59+
enum FloatConvRankCompareResult {
60+
FRCR_Unordered,
61+
FRCR_Lesser,
62+
FRCR_Greater,
63+
FRCR_Equal,
64+
FRCR_Equal_Lesser_Subrank,
65+
FRCR_Equal_Greater_Subrank,
66+
};
67+
5868
class APValue;
5969
class ASTMutationListener;
6070
class ASTRecordLayout;
@@ -1182,8 +1192,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
11821192
CanQualType SatUnsignedShortFractTy, SatUnsignedFractTy,
11831193
SatUnsignedLongFractTy;
11841194
CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON
1185-
CanQualType BFloat16Ty;
1186-
CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
1195+
CanQualType BFloat16Ty; // [C++23 6.8.3p5][basic.extended.fp]
1196+
CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3 and [C++23 6.8.3p1][basic.extended.fp]
11871197
CanQualType VoidPtrTy, NullPtrTy;
11881198
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnresolvedTemplateTy,
11891199
UnknownAnyTy;
@@ -2563,6 +2573,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
25632573
/// More type predicates useful for type checking/promotion
25642574
bool isPromotableIntegerType(QualType T) const; // C99 6.3.1.1p2
25652575

2576+
/// Determine if a floating type can be promoted to another floating type.
2577+
bool isPromotableFloatingType(QualType T) const;
2578+
25662579
/// Return the "preferred" alignment of the specified type \p T for
25672580
/// the current target, in bits.
25682581
///
@@ -2970,6 +2983,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
29702983
/// 6.3.1.1p2, assuming that \p PromotableType is a promotable integer type.
29712984
QualType getPromotedIntegerType(QualType PromotableType) const;
29722985

2986+
/// Determines the promoted floating point type.
2987+
QualType getPromotedFloatingType(QualType PromotableType) const;
2988+
29732989
/// Recurses in pointer/array types until it finds an Objective-C
29742990
/// retainable type and returns its ownership.
29752991
Qualifiers::ObjCLifetime getInnerObjCOwnership(QualType T) const;
@@ -2990,14 +3006,38 @@ class ASTContext : public RefCountedBase<ASTContext> {
29903006
/// Compare the rank of the two specified floating point types,
29913007
/// ignoring the domain of the type (i.e. 'double' == '_Complex double').
29923008
///
2993-
/// If \p LHS > \p RHS, returns 1. If \p LHS == \p RHS, returns 0. If
2994-
/// \p LHS < \p RHS, return -1.
2995-
int getFloatingTypeOrder(QualType LHS, QualType RHS) const;
3009+
/// If \p LHS > \p RHS, returns FRCR_Greater. If \p LHS == \p RHS, returns
3010+
/// FRCR_Equal. If \p LHS < \p RHS, return FRCR_Lesser. If \p LHS and \p RHS
3011+
/// are unordered, return FRCR_Unordered. If \p LHS and \p RHS are equal but
3012+
/// the subrank of \p LHS is greater than \p RHS, return
3013+
/// FRCR_Equal_Greater_Subrank. If \p LHS and \p RHS are equal but the subrank
3014+
/// of \p LHS is less than \p RHS, return FRCR_Equal_Lesser_Subrank. Subrank
3015+
/// and Unordered comparison were introduced in C++23.
3016+
FloatConvRankCompareResult getFloatingTypeOrder(QualType LHS,
3017+
QualType RHS) const;
29963018

29973019
/// Compare the rank of two floating point types as above, but compare equal
29983020
/// if both types have the same floating-point semantics on the target (i.e.
2999-
/// long double and double on AArch64 will return 0).
3000-
int getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const;
3021+
/// long double and double on AArch64 will return FRCR_Equal).
3022+
FloatConvRankCompareResult getFloatingTypeSemanticOrder(QualType LHS,
3023+
QualType RHS) const;
3024+
3025+
/// C++23 6.8.2p12 [basic.fundamental]
3026+
/// Checks if extended floating point rules apply to a pair of types.
3027+
/// It returns true if both the types are C++23 floating point types and
3028+
/// at least one of them is a C++23 extended floating point type. It returns
3029+
/// false for pairs of standard C++23 floating point types.
3030+
bool doCXX23ExtendedFpTypesRulesApply(QualType T1, QualType T2) const;
3031+
3032+
/// C++23 6.8.2p12 [basic.fundamental]
3033+
/// Returns true if \p Result is FRCR_Lesser or FRCR_Unordered rank.
3034+
bool
3035+
isCXX23SmallerOrUnorderedFloatingPointRank(FloatConvRankCompareResult Result) const;
3036+
3037+
/// C++23 6.8.2p12 [basic.fundamental]
3038+
/// Returns true if \p Result is FRCR_Equal, FRCR_Equal_Lesser_Subrank or
3039+
/// FRCR_Equal_Greater_Subrank.
3040+
bool isCXX23EqualFloatingPointRank(FloatConvRankCompareResult Result) const;
30013041

30023042
unsigned getTargetAddressSpace(LangAS AS) const;
30033043

clang/include/clang/AST/BuiltinTypes.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,10 @@ FLOATING_TYPE(Double, DoubleTy)
209209
// 'long double'
210210
FLOATING_TYPE(LongDouble, LongDoubleTy)
211211

212-
// '_Float16'
212+
// '_Float16', 'std::float16_t'
213213
FLOATING_TYPE(Float16, HalfTy)
214214

215-
// '__bf16'
215+
// '__bf16', 'std::bfloat16_t'
216216
FLOATING_TYPE(BFloat16, BFloat16Ty)
217217

218218
// '__float128'

clang/include/clang/AST/Type.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2513,6 +2513,13 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
25132513
bool isComplexType() const; // C99 6.2.5p11 (complex)
25142514
bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int.
25152515
bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
2516+
/// C++23 6.8.2p12 [basic.fundamental] (standard floating point + extended
2517+
/// floating point)
2518+
bool isCXX23FloatingPointType(const ASTContext &Ctx) const;
2519+
/// C++23 6.8.2p12 [basic.fundamental] (standard floating point)
2520+
bool isCXX23StandardFloatingPointType(const ASTContext &Ctx) const;
2521+
/// C++23 6.8.2p12 [basic.fundamental] (extended floating point)
2522+
bool isCXX23ExtendedFloatingPointType(const ASTContext &Ctx) const;
25162523
bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
25172524
bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661
25182525
bool isFloat32Type() const;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9278,6 +9278,8 @@ def err_cast_pointer_to_non_pointer_int : Error<
92789278
def err_nullptr_cast : Error<
92799279
"cannot cast an object of type %select{'nullptr_t' to %1|%1 to 'nullptr_t'}0"
92809280
>;
9281+
def err_invalid_implicit_floating_point_cast : Error<
9282+
"floating-point type %0 cannot be implicitly converted to type %1">;
92819283
def err_typecheck_expect_scalar_operand : Error<
92829284
"operand of type %0 where arithmetic or pointer type is required">;
92839285
def err_typecheck_cond_incompatible_operands : Error<

clang/include/clang/Lex/LiteralSupport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class NumericLiteralParser {
8282
bool isAccum : 1; // 1.0hk/k/lk/uhk/uk/ulk
8383
bool isBitInt : 1; // 1wb, 1uwb (C23) or 1__wb, 1__uwb (Clang extension in C++
8484
// mode)
85+
bool isBFloat16 : 1; // 1.0bf
8586
uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
8687

8788

clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H
1414
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H
1515

16+
#include "clang/AST/ASTContext.h"
1617
#include "clang/AST/Expr.h"
1718
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
1819
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -774,16 +775,24 @@ class SMTConv {
774775

775776
// If we have two real floating types, convert the smaller operand to the
776777
// bigger result
778+
// FIXME: It isn't clear how unordered and equal floating-point ranks should
779+
// FIXME: be handled here. For now, they are arbitrarily handled by adding a
780+
// FIXME: cast to the RHS to match the LHS.
777781
// Note: Safe to skip updating bitwidth because this must terminate
778-
int order = Ctx.getFloatingTypeOrder(LTy, RTy);
779-
if (order > 0) {
782+
FloatConvRankCompareResult order = Ctx.getFloatingTypeOrder(LTy, RTy);
783+
switch (order) {
784+
case FRCR_Unordered:
785+
case FRCR_Greater:
786+
case FRCR_Equal:
787+
case FRCR_Equal_Greater_Subrank:
780788
RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
781789
RTy = LTy;
782-
} else if (order == 0) {
790+
break;
791+
case FRCR_Lesser:
792+
case FRCR_Equal_Lesser_Subrank:
783793
LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
784794
LTy = RTy;
785-
} else {
786-
llvm_unreachable("Unsupported floating-point type cast!");
795+
break;
787796
}
788797
}
789798
};

clang/lib/AST/ASTContext.cpp

Lines changed: 139 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,84 @@ template <> struct llvm::DenseMapInfo<llvm::FoldingSetNodeID> {
132132
return LHS == RHS;
133133
}
134134
};
135+
constexpr unsigned CXX23FloatRankToIndex(clang::BuiltinType::Kind Kind) {
136+
switch (Kind) {
137+
case clang::BuiltinType::Float16:
138+
return 0;
139+
case clang::BuiltinType::BFloat16:
140+
return 1;
141+
case clang::BuiltinType::Float:
142+
return 2;
143+
case clang::BuiltinType::Double:
144+
return 3;
145+
case clang::BuiltinType::LongDouble:
146+
return 4;
147+
default:
148+
// Both __float128 and __ibm128 are compiler extensions, not extended floating points.
149+
// __float128 also predates the invention of floating-point types.
150+
llvm_unreachable("Not a CXX23+ floating point builtin type");
151+
}
152+
}
153+
154+
// C++23 6.8.6p2 [conv.rank]
155+
// Grid to determine the rank of a floating point type when compared with
156+
// another floating point type.
157+
constexpr std::array<std::array<FloatConvRankCompareResult, 5>, 5>
158+
CXX23FloatingPointConversionRankMap = {
159+
{// Float16 x Float16
160+
// Float16 x BFloat16
161+
// Float16 x Float
162+
// Float16 x Double
163+
// Float16 x LongDouble
164+
{{FloatConvRankCompareResult::FRCR_Equal,
165+
FloatConvRankCompareResult::FRCR_Unordered,
166+
FloatConvRankCompareResult::FRCR_Lesser,
167+
FloatConvRankCompareResult::FRCR_Lesser,
168+
FloatConvRankCompareResult::FRCR_Lesser}},
169+
170+
// BFloat16 x Float16
171+
// BFloat16 x BFloat16
172+
// BFloat16 x Float
173+
// BFloat16 x Double
174+
// BFloat16 x LongDouble
175+
{{FloatConvRankCompareResult::FRCR_Unordered,
176+
FloatConvRankCompareResult::FRCR_Equal,
177+
FloatConvRankCompareResult::FRCR_Lesser,
178+
FloatConvRankCompareResult::FRCR_Lesser,
179+
FloatConvRankCompareResult::FRCR_Lesser}},
180+
181+
// Float x Float16
182+
// Float x BFloat16
183+
// Float x Float
184+
// Float x Double
185+
// Float x LongDouble
186+
{{FloatConvRankCompareResult::FRCR_Greater,
187+
FloatConvRankCompareResult::FRCR_Greater,
188+
FloatConvRankCompareResult::FRCR_Equal,
189+
FloatConvRankCompareResult::FRCR_Lesser,
190+
FloatConvRankCompareResult::FRCR_Lesser}},
191+
192+
// Double x Float16
193+
// Double x BFloat16
194+
// Double x Float
195+
// Double x Double
196+
// Double x LongDouble
197+
{{FloatConvRankCompareResult::FRCR_Greater,
198+
FloatConvRankCompareResult::FRCR_Greater,
199+
FloatConvRankCompareResult::FRCR_Greater,
200+
FloatConvRankCompareResult::FRCR_Equal,
201+
FloatConvRankCompareResult::FRCR_Lesser}},
202+
203+
// LongDouble x Float16
204+
// LongDouble x BFloat16
205+
// LongDouble x Float
206+
// LongDouble x Double
207+
// LongDouble x LongDouble
208+
{{FloatConvRankCompareResult::FRCR_Greater,
209+
FloatConvRankCompareResult::FRCR_Greater,
210+
FloatConvRankCompareResult::FRCR_Greater,
211+
FloatConvRankCompareResult::FRCR_Greater,
212+
FloatConvRankCompareResult::FRCR_Equal}}}};
135213

136214
/// \returns The locations that are relevant when searching for Doc comments
137215
/// related to \p D.
@@ -1917,6 +1995,10 @@ bool ASTContext::isPromotableIntegerType(QualType T) const {
19171995
return false;
19181996
}
19191997

1998+
bool ASTContext::isPromotableFloatingType(QualType T) const {
1999+
return T->getAs<BuiltinType>()->getKind() == BuiltinType::Float;
2000+
}
2001+
19202002
bool ASTContext::isAlignmentRequired(const Type *T) const {
19212003
return getTypeInfo(T).AlignRequirement != AlignRequirementKind::None;
19222004
}
@@ -7670,27 +7752,69 @@ static FloatingRank getFloatingRank(QualType T) {
76707752
}
76717753
}
76727754

7755+
/// C++23 6.8.5 [conv.rank]
76737756
/// getFloatingTypeOrder - Compare the rank of the two specified floating
76747757
/// point types, ignoring the domain of the type (i.e. 'double' ==
7675-
/// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If
7676-
/// LHS < RHS, return -1.
7677-
int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const {
7758+
/// '_Complex double').
7759+
/// If LHS > RHS, return FRCR_Greater. If LHS == RHS, return FRCR_Equal. If
7760+
/// LHS < RHS, return FRCR_Lesser. If the values representedable by the two
7761+
/// are not subset of each other, return FRCR_Unordered. If LHS == RHS but
7762+
/// LHS has a higher subrank than RHS return FRCR_Equal_Greater_Subrank else
7763+
/// return FRCR_Equal_Lesser_Subrank.
7764+
FloatConvRankCompareResult
7765+
ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const {
7766+
if (LHS->isCXX23FloatingPointType(*this) &&
7767+
RHS->isCXX23FloatingPointType(*this)) {
7768+
BuiltinType::Kind LHSKind;
7769+
BuiltinType::Kind RHSKind;
7770+
if (const auto *CT = LHS->getAs<ComplexType>())
7771+
LHSKind = CT->getElementType()->castAs<BuiltinType>()->getKind();
7772+
else
7773+
LHSKind = LHS->castAs<BuiltinType>()->getKind();
7774+
if (const auto *CT = RHS->getAs<ComplexType>())
7775+
RHSKind = CT->getElementType()->castAs<BuiltinType>()->getKind();
7776+
else
7777+
RHSKind = RHS->castAs<BuiltinType>()->getKind();
7778+
return CXX23FloatingPointConversionRankMap[CXX23FloatRankToIndex(LHSKind)]
7779+
[CXX23FloatRankToIndex(RHSKind)];
7780+
}
7781+
76787782
FloatingRank LHSR = getFloatingRank(LHS);
76797783
FloatingRank RHSR = getFloatingRank(RHS);
76807784

76817785
if (LHSR == RHSR)
7682-
return 0;
7786+
return FRCR_Equal;
76837787
if (LHSR > RHSR)
7684-
return 1;
7685-
return -1;
7788+
return FRCR_Greater;
7789+
return FRCR_Lesser;
76867790
}
76877791

7688-
int ASTContext::getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const {
7792+
FloatConvRankCompareResult
7793+
ASTContext::getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const {
76897794
if (&getFloatTypeSemantics(LHS) == &getFloatTypeSemantics(RHS))
7690-
return 0;
7795+
return FRCR_Equal;
76917796
return getFloatingTypeOrder(LHS, RHS);
76927797
}
76937798

7799+
bool ASTContext::doCXX23ExtendedFpTypesRulesApply(QualType T1,
7800+
QualType T2) const {
7801+
return (((T1->isCXX23FloatingPointType(*this) &&
7802+
T2->isCXX23FloatingPointType(*this))) &&
7803+
(T1->isCXX23ExtendedFloatingPointType(*this) ||
7804+
T2->isCXX23ExtendedFloatingPointType(*this)));
7805+
}
7806+
7807+
bool ASTContext::isCXX23SmallerOrUnorderedFloatingPointRank(
7808+
FloatConvRankCompareResult Result) const {
7809+
return (Result == FRCR_Lesser) || (Result == FRCR_Unordered);
7810+
}
7811+
7812+
bool ASTContext::isCXX23EqualFloatingPointRank(
7813+
FloatConvRankCompareResult Result) const {
7814+
return (Result == FRCR_Equal) || (Result == FRCR_Equal_Greater_Subrank) ||
7815+
(Result == FRCR_Equal_Lesser_Subrank);
7816+
}
7817+
76947818
/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
76957819
/// routine will assert if passed a built-in type that isn't an integer or enum,
76967820
/// or if it is not canonicalized.
@@ -7853,6 +7977,13 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
78537977
return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy;
78547978
}
78557979

7980+
QualType ASTContext::getPromotedFloatingType(QualType Promotable) const {
7981+
assert(!Promotable.isNull());
7982+
assert(isPromotableFloatingType(Promotable));
7983+
assert(Promotable->getAs<BuiltinType>()->getKind() == BuiltinType::Float);
7984+
return DoubleTy;
7985+
}
7986+
78567987
/// Recurses in pointer/array types until it finds an objc retainable
78577988
/// type and returns its ownership.
78587989
Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const {

clang/lib/AST/StmtPrinter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,7 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
14581458
case BuiltinType::Float: OS << 'F'; break;
14591459
case BuiltinType::LongDouble: OS << 'L'; break;
14601460
case BuiltinType::Float128: OS << 'Q'; break;
1461+
case BuiltinType::BFloat16: OS << "BF16"; break;
14611462
}
14621463
}
14631464

0 commit comments

Comments
 (0)