[clang] [Clang][C++23] Implement core language changes from P1467R9 extended floating-point types and standard names. (PR #78503)
M. Zeeshan Siddiqui via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 17 13:13:37 PST 2024
https://github.com/codemzs created https://github.com/llvm/llvm-project/pull/78503
Implements Core language changes based on [P1467R9](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1467r9.html) 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
This pull request is a carryover from the now offline phabricator differential revision: https://reviews.llvm.org/D149573
>From d47d92d074e6a4870849db79dec5adb197bed010 Mon Sep 17 00:00:00 2001
From: "M. Zeeshan Siddiqui" <mzs at microsoft.com>
Date: Mon, 13 Nov 2023 17:37:36 +0000
Subject: [PATCH] [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
---
clang/include/clang/AST/ASTContext.h | 48 +-
clang/include/clang/AST/Type.h | 7 +
.../clang/Basic/DiagnosticSemaKinds.td | 1 +
clang/include/clang/Lex/LiteralSupport.h | 1 +
.../Core/PathSensitive/SMTConv.h | 7 +-
clang/lib/AST/ASTContext.cpp | 137 ++++-
clang/lib/AST/StmtPrinter.cpp | 1 +
clang/lib/AST/Type.cpp | 27 +
clang/lib/Frontend/InitPreprocessor.cpp | 6 +-
clang/lib/Lex/LiteralSupport.cpp | 17 +
clang/lib/Sema/Sema.cpp | 17 +
clang/lib/Sema/SemaCast.cpp | 13 +
clang/lib/Sema/SemaChecking.cpp | 17 +-
clang/lib/Sema/SemaExpr.cpp | 60 ++-
clang/lib/Sema/SemaOverload.cpp | 81 ++-
.../cxx23-fp-ext-std-names-p1467r9.cpp | 499 +++++++++++++++++
.../test/CodeGenCXX/cxx23-vector-bfloat16.cpp | 67 +++
.../Sema/cxx23-fp-ext-std-names-p1467r9.cpp | 505 ++++++++++++++++++
18 files changed, 1471 insertions(+), 40 deletions(-)
create mode 100644 clang/test/CodeGenCXX/cxx23-fp-ext-std-names-p1467r9.cpp
create mode 100644 clang/test/CodeGenCXX/cxx23-vector-bfloat16.cpp
create mode 100644 clang/test/Sema/cxx23-fp-ext-std-names-p1467r9.cpp
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 3e46a5da3fc043..beec40b4a8197b 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -52,6 +52,16 @@ template <typename T, unsigned N> class SmallPtrSet;
namespace clang {
+// Conversion ranks introduced in C++23 6.8.6p2 [conv.rank]
+enum FloatingRankCompareResult {
+ FRCR_Unordered,
+ FRCR_Lesser,
+ FRCR_Greater,
+ FRCR_Equal,
+ FRCR_Equal_Lesser_Subrank,
+ FRCR_Equal_Greater_Subrank,
+};
+
class APValue;
class ASTMutationListener;
class ASTRecordLayout;
@@ -1105,8 +1115,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
CanQualType SatUnsignedShortFractTy, SatUnsignedFractTy,
SatUnsignedLongFractTy;
CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON
- CanQualType BFloat16Ty;
- CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
+ CanQualType BFloat16Ty; // [C++23 6.8.3p5][basic.extended.fp]
+ CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3 and [C++23 6.8.3p5][basic.extended.fp]
CanQualType VoidPtrTy, NullPtrTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
CanQualType BuiltinFnTy;
@@ -2803,14 +2813,38 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Compare the rank of the two specified floating point types,
/// ignoring the domain of the type (i.e. 'double' == '_Complex double').
///
- /// If \p LHS > \p RHS, returns 1. If \p LHS == \p RHS, returns 0. If
- /// \p LHS < \p RHS, return -1.
- int getFloatingTypeOrder(QualType LHS, QualType RHS) const;
+ /// If \p LHS > \p RHS, returns FRCR_Greater. If \p LHS == \p RHS, returns
+ /// FRCR_Equal. If \p LHS < \p RHS, return FRCR_Lesser. If \p LHS and \p RHS
+ /// are unordered, return FRCR_Unordered. If \p LHS and \p RHS are equal but
+ /// the subrank of \p LHS is greater than \p RHS, return
+ /// FRCR_Equal_Greater_Subrank. If \p LHS and \p RHS are equal but the subrank
+ /// of \p LHS is less than \p RHS, return FRCR_Equal_Lesser_Subrank. Subrank
+ /// and Unordered comparison were introduced in C++23.
+ FloatingRankCompareResult getFloatingTypeOrder(QualType LHS,
+ QualType RHS) const;
/// Compare the rank of two floating point types as above, but compare equal
/// if both types have the same floating-point semantics on the target (i.e.
- /// long double and double on AArch64 will return 0).
- int getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const;
+ /// long double and double on AArch64 will return FRCR_Equal).
+ FloatingRankCompareResult getFloatingTypeSemanticOrder(QualType LHS,
+ QualType RHS) const;
+
+ /// C++23 6.8.2p12 [basic.fundamental]
+ /// Checks if extended floating point rules apply to a pair of types.
+ /// It returns true if both the types are C++23 floating point types and
+ /// at least one of them is a C++23 extended floating point type. It returns
+ /// false for pairs of standard C++23 floating point types.
+ bool doCXX23ExtendedFpTypesRulesApply(QualType T1, QualType T2) const;
+
+ /// C++23 6.8.2p12 [basic.fundamental]
+ /// Returns true if \p Result is FRCR_Lesser or FRCR_Unordered rank.
+ bool
+ isCXX23SmallerOrUnorderedFloatingPointRank(FloatingRankCompareResult Result) const;
+
+ /// C++23 6.8.2p12 [basic.fundamental]
+ /// Returns true if \p Result is FRCR_Equal, FRCR_Equal_Lesser_Subrank or
+ /// FRCR_Equal_Greater_Subrank.
+ bool isCXX23EqualFloatingPointRank(FloatingRankCompareResult Result) const;
unsigned getTargetAddressSpace(LangAS AS) const;
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index a7efe78591635e..5dc3ac9e3c7498 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2242,6 +2242,13 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isComplexType() const; // C99 6.2.5p11 (complex)
bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int.
bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
+ /// C++23 6.8.2p12 [basic.fundamental] (standard floating point + extended
+ /// floating point)
+ bool isCXX23FloatingPointType(const ASTContext &Ctx) const;
+ /// C++23 6.8.2p12 [basic.fundamental] (standard floating point)
+ bool isCXX23StandardFloatingPointType(const ASTContext &Ctx) const;
+ /// C++23 6.8.2p12 [basic.fundamental] (extended floating point)
+ bool isCXX23ExtendedFloatingPointType(const ASTContext &Ctx) const;
bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661
bool isBFloat16Type() const;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 03b0122d1c08f7..d635ea14004284 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8982,6 +8982,7 @@ def err_cast_pointer_to_non_pointer_int : Error<
def err_nullptr_cast : Error<
"cannot cast an object of type %select{'nullptr_t' to %1|%1 to 'nullptr_t'}0"
>;
+def err_cxx23_invalid_implicit_floating_point_cast : Error<"floating point cast results in loss of precision">;
def err_typecheck_expect_scalar_operand : Error<
"operand of type %0 where arithmetic or pointer type is required">;
def err_typecheck_cond_incompatible_operands : Error<
diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h
index 643ddbdad8c87d..c1301e56af97f3 100644
--- a/clang/include/clang/Lex/LiteralSupport.h
+++ b/clang/include/clang/Lex/LiteralSupport.h
@@ -81,6 +81,7 @@ class NumericLiteralParser {
bool isFract : 1; // 1.0hr/r/lr/uhr/ur/ulr
bool isAccum : 1; // 1.0hk/k/lk/uhk/uk/ulk
bool isBitInt : 1; // 1wb, 1uwb (C23)
+ bool isBFloat16 : 1; // 1.0bf
uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
index fcc9c02999b3b0..b2cd4cd7c76f12 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -775,11 +776,11 @@ class SMTConv {
// If we have two real floating types, convert the smaller operand to the
// bigger result
// Note: Safe to skip updating bitwidth because this must terminate
- int order = Ctx.getFloatingTypeOrder(LTy, RTy);
- if (order > 0) {
+ FloatingRankCompareResult order = Ctx.getFloatingTypeOrder(LTy, RTy);
+ if ((order == FRCR_Greater) || (order == FRCR_Equal_Greater_Subrank)) {
RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
RTy = LTy;
- } else if (order == 0) {
+ } else if ((order == FRCR_Equal) || (order == FRCR_Equal_Lesser_Subrank)) {
LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
LTy = RTy;
} else {
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index d9cefcaa84d7e5..989dee9fca148d 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -112,6 +112,85 @@ enum FloatingRank {
Ibm128Rank
};
+constexpr unsigned CXX23FloatRankToIndex(clang::BuiltinType::Kind Kind) {
+ switch (Kind) {
+ case clang::BuiltinType::Float16:
+ return 0;
+ case clang::BuiltinType::BFloat16:
+ return 1;
+ case clang::BuiltinType::Float:
+ return 2;
+ case clang::BuiltinType::Double:
+ return 3;
+ case clang::BuiltinType::LongDouble:
+ return 4;
+ default:
+ // Both __float128 and __ibm128 are compiler extensions, not extended floating points.
+ // __float128 also predates the invention of floating-point types.
+ llvm_unreachable("Not a CXX23+ floating point builtin type");
+ }
+}
+
+// C++23 6.8.6p2 [conv.rank]
+// Grid to determine the rank of a floating point type when compared with
+// another floating point type.
+constexpr std::array<std::array<FloatingRankCompareResult, 5>, 5>
+ CXX23FloatingPointConversionRankMap = {
+ {// Float16 x Float16
+ // Float16 x BFloat16
+ // Float16 x Float
+ // Float16 x Double
+ // Float16 x LongDouble
+ {{FloatingRankCompareResult::FRCR_Equal,
+ FloatingRankCompareResult::FRCR_Unordered,
+ FloatingRankCompareResult::FRCR_Lesser,
+ FloatingRankCompareResult::FRCR_Lesser,
+ FloatingRankCompareResult::FRCR_Lesser}},
+
+ // BFloat16 x Float16
+ // BFloat16 x BFloat16
+ // BFloat16 x Float
+ // BFloat16 x Double
+ // BFloat16 x LongDouble
+ {{FloatingRankCompareResult::FRCR_Unordered,
+ FloatingRankCompareResult::FRCR_Equal,
+ FloatingRankCompareResult::FRCR_Lesser,
+ FloatingRankCompareResult::FRCR_Lesser,
+ FloatingRankCompareResult::FRCR_Lesser}},
+
+ // Float x Float16
+ // Float x BFloat16
+ // Float x Float
+ // Float x Double
+ // Float x LongDouble
+ {{FloatingRankCompareResult::FRCR_Greater,
+ FloatingRankCompareResult::FRCR_Greater,
+ FloatingRankCompareResult::FRCR_Equal,
+ FloatingRankCompareResult::FRCR_Lesser,
+ FloatingRankCompareResult::FRCR_Lesser}},
+
+ // Double x Float16
+ // Double x BFloat16
+ // Double x Float
+ // Double x Double
+ // Double x LongDouble
+ {{FloatingRankCompareResult::FRCR_Greater,
+ FloatingRankCompareResult::FRCR_Greater,
+ FloatingRankCompareResult::FRCR_Greater,
+ FloatingRankCompareResult::FRCR_Equal,
+ FloatingRankCompareResult::FRCR_Lesser}},
+
+ // LongDouble x Float16
+ // LongDouble x BFloat16
+ // LongDouble x Float
+ // LongDouble x Double
+ // LongDouble x LongDouble
+ {{FloatingRankCompareResult::FRCR_Greater,
+ FloatingRankCompareResult::FRCR_Greater,
+ FloatingRankCompareResult::FRCR_Greater,
+ FloatingRankCompareResult::FRCR_Greater,
+ FloatingRankCompareResult::FRCR_Equal}}}};
+
/// \returns The locations that are relevant when searching for Doc comments
/// related to \p D.
static SmallVector<SourceLocation, 2>
@@ -7007,27 +7086,69 @@ static FloatingRank getFloatingRank(QualType T) {
}
}
+/// C++23 6.8.5 [conv.rank]
/// getFloatingTypeOrder - Compare the rank of the two specified floating
/// point types, ignoring the domain of the type (i.e. 'double' ==
-/// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If
-/// LHS < RHS, return -1.
-int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const {
+/// '_Complex double').
+/// If LHS > RHS, return FRCR_Greater. If LHS == RHS, return FRCR_Equal. If
+/// LHS < RHS, return FRCR_Lesser. If the values representedable by the two
+/// are not subset of each other, return FRCR_Unordered. If LHS == RHS but
+/// LHS has a higher subrank than RHS return FRCR_Equal_Greater_Subrank else
+/// return FRCR_Equal_Lesser_Subrank.
+FloatingRankCompareResult ASTContext::getFloatingTypeOrder(QualType LHS,
+ QualType RHS) const {
+ if (LHS->isCXX23FloatingPointType(*this) &&
+ RHS->isCXX23FloatingPointType(*this)) {
+ BuiltinType::Kind LHSKind;
+ BuiltinType::Kind RHSKind;
+ if (const auto *CT = LHS->getAs<ComplexType>())
+ LHSKind = CT->getElementType()->castAs<BuiltinType>()->getKind();
+ else
+ LHSKind = LHS->castAs<BuiltinType>()->getKind();
+ if (const auto *CT = RHS->getAs<ComplexType>())
+ RHSKind = CT->getElementType()->castAs<BuiltinType>()->getKind();
+ else
+ RHSKind = RHS->castAs<BuiltinType>()->getKind();
+ return CXX23FloatingPointConversionRankMap[CXX23FloatRankToIndex(LHSKind)]
+ [CXX23FloatRankToIndex(RHSKind)];
+ }
+
FloatingRank LHSR = getFloatingRank(LHS);
FloatingRank RHSR = getFloatingRank(RHS);
if (LHSR == RHSR)
- return 0;
+ return FRCR_Equal;
if (LHSR > RHSR)
- return 1;
- return -1;
+ return FRCR_Greater;
+ return FRCR_Lesser;
}
-int ASTContext::getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const {
+FloatingRankCompareResult
+ASTContext::getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const {
if (&getFloatTypeSemantics(LHS) == &getFloatTypeSemantics(RHS))
- return 0;
+ return FRCR_Equal;
return getFloatingTypeOrder(LHS, RHS);
}
+bool ASTContext::doCXX23ExtendedFpTypesRulesApply(QualType T1,
+ QualType T2) const {
+ return (((T1->isCXX23FloatingPointType(*this) &&
+ T2->isCXX23FloatingPointType(*this))) &&
+ (T1->isCXX23ExtendedFloatingPointType(*this) ||
+ T2->isCXX23ExtendedFloatingPointType(*this)));
+}
+
+bool ASTContext::isCXX23SmallerOrUnorderedFloatingPointRank(
+ FloatingRankCompareResult Result) const {
+ return (Result == FRCR_Lesser) || (Result == FRCR_Unordered);
+}
+
+bool ASTContext::isCXX23EqualFloatingPointRank(
+ FloatingRankCompareResult Result) const {
+ return (Result == FRCR_Equal) || (Result == FRCR_Equal_Greater_Subrank) ||
+ (Result == FRCR_Equal_Lesser_Subrank);
+}
+
/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
/// routine will assert if passed a built-in type that isn't an integer or enum,
/// or if it is not canonicalized.
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index c04cb313c3387a..b762b581857abf 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1358,6 +1358,7 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
case BuiltinType::Float: OS << 'F'; break;
case BuiltinType::LongDouble: OS << 'L'; break;
case BuiltinType::Float128: OS << 'Q'; break;
+ case BuiltinType::BFloat16: OS << "BF16"; break;
}
}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index b419fc8836b032..d15b04e46a9c5c 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2192,6 +2192,33 @@ bool Type::isFloatingType() const {
return false;
}
+bool Type::isCXX23StandardFloatingPointType(const ASTContext &Ctx) const {
+ if (!Ctx.getLangOpts().CPlusPlus23)
+ return false;
+ if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Float &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ if (const auto *CT = dyn_cast<ComplexType>(CanonicalType))
+ return CT->getElementType()->isCXX23StandardFloatingPointType(Ctx);
+ return false;
+}
+
+bool Type::isCXX23ExtendedFloatingPointType(const ASTContext &Ctx) const {
+ if (!Ctx.getLangOpts().CPlusPlus23)
+ return false;
+ if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Float16 ||
+ BT->getKind() == BuiltinType::BFloat16;
+ if (const auto *CT = dyn_cast<ComplexType>(CanonicalType))
+ return CT->getElementType()->isCXX23ExtendedFloatingPointType(Ctx);
+ return false;
+}
+
+bool Type::isCXX23FloatingPointType(const ASTContext &Ctx) const {
+ return isCXX23StandardFloatingPointType(Ctx) ||
+ isCXX23ExtendedFloatingPointType(Ctx);
+}
+
bool Type::hasFloatingRepresentation() const {
if (const auto *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isFloatingType();
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index d83128adb511ef..f22ba2f5eae8f2 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -453,8 +453,12 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
if (LangOpts.CPlusPlus26)
// FIXME: Use correct value for C++26.
Builder.defineMacro("__cplusplus", "202400L");
- else if (LangOpts.CPlusPlus23)
+ else if (LangOpts.CPlusPlus23) {
Builder.defineMacro("__cplusplus", "202302L");
+ // [C++23] 15.11p2 [cpp.predefined]
+ Builder.defineMacro("__STDCPP_FLOAT16_T__", "1");
+ Builder.defineMacro("__STDCPP_BFLOAT16_T__", "1");
+ }
// [C++20] The integer literal 202002L.
else if (LangOpts.CPlusPlus20)
Builder.defineMacro("__cplusplus", "202002L");
diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index 0a78638f680511..21734c2c19fb54 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -925,6 +925,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
isAccum = false;
hadError = false;
isBitInt = false;
+ isBFloat16 = false;
// This routine assumes that the range begin/end matches the regex for integer
// and FP constants (specifically, the 'pp-number' regex), and assumes that
@@ -1029,6 +1030,21 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
isFloat = true;
continue; // Success.
+ // C++23 5.13.4 [lex.fcon]
+ case 'b':
+ case 'B':
+ if (!isFPConstant)
+ break; // Error for integer constant.
+ if (s + 3 < ThisTokEnd && (s[1] == 'f' || s[1] == 'F') && s[2] == '1' &&
+ s[3] == '6') {
+ if (HasSize)
+ break;
+ HasSize = true;
+ s += 3;
+ isBFloat16 = true;
+ continue;
+ }
+ break;
case 'q': // FP Suffix for "__float128"
case 'Q':
if (!isFPConstant) break; // Error for integer constant.
@@ -1161,6 +1177,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
saw_fixed_point_suffix = false;
isFract = false;
isAccum = false;
+ isBFloat16 = false;
}
saw_ud_suffix = true;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index cafbecebc8a119..e8aeca735260c0 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -700,6 +700,23 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
}
}
+ // C++23 7.3.10 [conv.double]
+ // A prvalue of floating-point type can be converted to a prvalue of another
+ // floating-point type with a greater or equal conversion rank ([conv.rank]).
+ // A prvalue of standard floating-point type can be converted to a prvalue of
+ // another standard floating-point type
+ if (Context.doCXX23ExtendedFpTypesRulesApply(ExprTy, TypeTy) &&
+ Kind == CK_FloatingCast && E->isPRValue() &&
+ (CCK == CCK_ImplicitConversion)) {
+ if (Context.isCXX23SmallerOrUnorderedFloatingPointRank(
+ Context.getFloatingTypeOrder(TypeTy, ExprTy))) {
+ Diag(E->getExprLoc(),
+ diag::err_cxx23_invalid_implicit_floating_point_cast)
+ << E->getSourceRange();
+ return ExprError();
+ }
+ }
+
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {
if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) {
ImpCast->setType(Ty);
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 9d85568d97b2d2..c905d11b8af82a 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -1386,6 +1386,19 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
}
}
+ // [expr.static.cast] 7.6.1.9p11, A prvalue of floating-point type can
+ // be explicitly converted to any other floating-point type.
+ // Conversion between fp16 and bf16 is not supported yet.
+ if (SrcExpr.get()->isPRValue() &&
+ Self.Context.doCXX23ExtendedFpTypesRulesApply(DestType, SrcType)) {
+ // FIXME: Support for cast between fp16 and bf16 doesn't exist yet.
+ if (!((DestType->isBFloat16Type() || DestType->isFloat16Type()) &&
+ (SrcType->isBFloat16Type() || SrcType->isFloat16Type()))) {
+ Kind = CK_FloatingCast;
+ return TC_Success;
+ }
+ }
+
// Reverse integral promotion/conversion. All such conversions are themselves
// again integral promotions or conversions and are thus already handled by
// p2 (TryDirectInitialization above).
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ace3e386988f00..47d2fdb9387f67 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11962,7 +11962,7 @@ isArithmeticArgumentPromotion(Sema &S, const ImplicitCastExpr *ICE) {
To = VecTy->getElementType();
// It's a floating promotion if the source type is a lower rank.
return ICE->getCastKind() == CK_FloatingCast &&
- S.Context.getFloatingTypeOrder(From, To) < 0;
+ S.Context.getFloatingTypeOrder(From, To) == FRCR_Lesser;
}
bool
@@ -15272,9 +15272,12 @@ static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) {
return;
// If both source and target are floating points, warn about losing precision.
- int Order = S.getASTContext().getFloatingTypeSemanticOrder(
- QualType(ResultBT, 0), QualType(RBT, 0));
- if (Order < 0 && !S.SourceMgr.isInSystemMacro(E->getOperatorLoc()))
+ FloatingRankCompareResult Order =
+ S.getASTContext().getFloatingTypeSemanticOrder(QualType(ResultBT, 0),
+ QualType(RBT, 0));
+
+ assert(Order != FRCR_Unordered && "Invalid floating point types");
+ if (Order == FRCR_Lesser && !S.SourceMgr.isInSystemMacro(E->getOperatorLoc()))
// warn about dropping FP rank.
DiagnoseImpCast(S, E->getRHS(), E->getLHS()->getType(), E->getOperatorLoc(),
diag::warn_impcast_float_result_precision);
@@ -15700,7 +15703,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
int Order = S.getASTContext().getFloatingTypeSemanticOrder(
QualType(SourceBT, 0), QualType(TargetBT, 0));
- if (Order > 0) {
+ if (Order == FRCR_Greater) {
// Don't warn about float constants that are precisely
// representable in the target type.
Expr::EvalResult result;
@@ -15718,12 +15721,14 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision);
}
// ... or possibly if we're increasing rank, too
- else if (Order < 0) {
+ else if (Order == FRCR_Lesser) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_double_promotion);
}
+ assert(Order != FRCR_Unordered &&
+ "Unordered floating types are not allowed.");
return;
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 1b7a6bef336064..beb151bf9fee24 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -809,7 +809,7 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
llvm_unreachable("Float evaluation method should be set by now");
break;
case LangOptions::FEM_Double:
- if (Context.getFloatingTypeOrder(Context.DoubleTy, Ty) > 0)
+ if (Context.getFloatingTypeOrder(Context.DoubleTy, Ty) == FRCR_Greater)
// Widen the expression to double.
return Ty->isComplexType()
? ImpCastExprToType(E,
@@ -818,7 +818,8 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
: ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast);
break;
case LangOptions::FEM_Extended:
- if (Context.getFloatingTypeOrder(Context.LongDoubleTy, Ty) > 0)
+ if (Context.getFloatingTypeOrder(Context.LongDoubleTy, Ty) ==
+ FRCR_Greater)
// Widen the expression to long double.
return Ty->isComplexType()
? ImpCastExprToType(
@@ -1169,14 +1170,16 @@ static QualType handleComplexConversion(Sema &S, ExprResult &LHS,
return RHSType;
// Compute the rank of the two types, regardless of whether they are complex.
- int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType);
- if (Order < 0)
+ FloatingRankCompareResult Order =
+ S.Context.getFloatingTypeOrder(LHSType, RHSType);
+ if (Order == FRCR_Lesser)
// Promote the precision of the LHS if not an assignment.
return handleComplexFloatConversion(S, LHS, LHSType, RHSType,
/*PromotePrecision=*/!IsCompAssign);
// Promote the precision of the RHS unless it is already the same as the LHS.
return handleComplexFloatConversion(S, RHS, RHSType, LHSType,
- /*PromotePrecision=*/Order > 0);
+ /*PromotePrecision=*/Order ==
+ clang::FRCR_Greater);
}
/// Handle arithmetic conversion from integer to float. Helper function
@@ -1229,16 +1232,34 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
return LHSFloat ? LHSType : RHSType;
}
- // If we have two real floating types, convert the smaller operand
- // to the bigger result.
+ // C++23 [expr.arith.conv] 7.4
+ // If the floating-point conversion ranks ([conv.rank]) of the types
+ // of the operands are ordered but not equal, then the operand of the type
+ // with the lesser floating-point conversion rank is converted to the type of
+ // the other operand.
+ //
+ // If the floating-point conversion ranks of the types of the operands are
+ // equal, then the operand with the lesser floating-point conversion subrank
+ // ([conv.rank]) is converted to the type of the other operand.
+ //
+ // Otherwise, the expression is ill-formed i.e unordered conversion rank
+ // between floating-point types.
if (LHSFloat && RHSFloat) {
- int order = S.Context.getFloatingTypeOrder(LHSType, RHSType);
- if (order > 0) {
+ FloatingRankCompareResult order =
+ S.Context.getFloatingTypeOrder(LHSType, RHSType);
+
+ if (order == FRCR_Unordered) {
+ return QualType();
+ }
+
+ if (order == FRCR_Greater || order == FRCR_Equal_Greater_Subrank) {
RHS = S.ImpCastExprToType(RHS.get(), LHSType, CK_FloatingCast);
return LHSType;
}
- assert(order < 0 && "illegal float comparison");
+ assert(((order != FRCR_Equal) &&
+ (order == FRCR_Lesser || order == FRCR_Equal_Lesser_Subrank)) &&
+ "illegal float comparison");
if (!IsCompAssign)
LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FloatingCast);
return RHSType;
@@ -4107,6 +4128,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Ty = Context.Float16Ty;
else if (Literal.isFloat128)
Ty = Context.Float128Ty;
+ else if (Literal.isBFloat16)
+ Ty = Context.BFloat16Ty;
else
Ty = Context.DoubleTy;
@@ -10841,7 +10864,8 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar,
} else if (vectorEltTy->isRealFloatingType()) {
if (scalarTy->isRealFloatingType()) {
if (S.getLangOpts().OpenCL &&
- S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy) < 0) {
+ S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy) ==
+ clang::FRCR_Lesser) {
DiagID = diag::err_opencl_scalar_type_rank_greater_than_vector_type;
return true;
}
@@ -11029,8 +11053,18 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
// expression is instantiated.
bool CstScalar = Scalar->get()->isValueDependent() ||
Scalar->get()->EvaluateAsFloat(Result, S.Context);
- int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy);
- if (!CstScalar && Order < 0)
+ FloatingRankCompareResult Order =
+ S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy);
+
+ // Although the GCC Vector Extensions are not part of the C++23 language
+ // standard, we are currently applying the C++23 extended floating point
+ // rules to them. This is in keeping with the spirit of this function and
+ // maintains consistency in handling floating point types
+ if (S.Context.doCXX23ExtendedFpTypesRulesApply(ScalarTy, VectorEltTy) &&
+ S.Context.isCXX23SmallerOrUnorderedFloatingPointRank(Order))
+ return true;
+
+ if (!CstScalar && (Order == FRCR_Lesser))
return true;
// If the scalar cannot be safely casted to the vector element type,
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 37c62b306b3cd3..ba9cf196bfe04e 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -402,7 +402,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
// if it cannot be represented exactly), or
case ICK_Floating_Conversion:
if (FromType->isRealFloatingType() && ToType->isRealFloatingType() &&
- Ctx.getFloatingTypeOrder(FromType, ToType) == 1) {
+ Ctx.getFloatingTypeOrder(FromType, ToType) == FRCR_Greater) {
// FromType is larger than ToType.
const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
@@ -2107,6 +2107,16 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
(FromType->isFloat16Type() || FromType->isHalfType())))
return false;
+ // C++23 7.3.10p1 [conv.double]
+ // A prvalue of floating-point type can be converted to a prvalue of another
+ // floating-point type with a greater or equal conversion rank
+ // ([conv.rank]). A prvalue of standard floating-point type can be converted
+ // to a prvalue of another standard floating-point type.
+ if (S.Context.doCXX23ExtendedFpTypesRulesApply(FromType, ToType) &&
+ S.Context.isCXX23SmallerOrUnorderedFloatingPointRank(
+ S.Context.getFloatingTypeOrder(ToType, FromType)))
+ return false;
+
// Conversions between IEEE-quad and IBM-extended semantics are not
// permitted.
const llvm::fltSemantics &FromSem =
@@ -4305,6 +4315,73 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
+ // C++23 12.2.4.3p4:
+ // A conversion in either direction between floating-point type FP1 and
+ // floating-point type FP2 is better than a conversion in the same direction
+ // between FP1 and arithmetic type T3 if:
+ // 1) The floating-point conversion rank ([conv.rank]) of FP1 is equal to the
+ // rank of FP2, and 2) T3 is not a floating-point type, or T3 is a
+ // floating-point type whose rank is not equal to the rank of FP1, or the
+ // floating-point conversion subrank ([conv.rank]) of FP2 is greater than the
+ // subrank of T3.
+ if (S.Context.getLangOpts().CPlusPlus23) {
+ if (SCS1.getFromType()->isCXX23FloatingPointType(S.Context) &&
+ S.Context.hasSameType(SCS1.getFromType(), SCS2.getFromType())) {
+
+ if ((SCS1.Second == ICK_Floating_Conversion) &&
+ SCS1.getToType(1)->isCXX23FloatingPointType(S.Context) &&
+ S.Context.isCXX23EqualFloatingPointRank(
+ S.Context.getFloatingTypeOrder(SCS1.getToType(1),
+ SCS1.getFromType()))) {
+
+ if (SCS2.getToType(1)->isArithmeticType()) {
+ if (!SCS2.getToType(1)->isCXX23FloatingPointType(S.Context)) {
+ return ImplicitConversionSequence::Better;
+ }
+
+ if (!S.Context.isCXX23EqualFloatingPointRank(
+ S.Context.getFloatingTypeOrder(SCS2.getToType(1),
+ SCS1.getFromType()))) {
+ return ImplicitConversionSequence::Better;
+ }
+
+ if (S.Context.getFloatingTypeOrder(SCS1.getToType(1),
+ SCS2.getToType(1)) ==
+ FRCR_Equal_Greater_Subrank) {
+ return ImplicitConversionSequence::Better;
+ }
+ return ImplicitConversionSequence::Worse;
+ }
+ }
+
+ if ((SCS2.Second == ICK_Floating_Conversion) &&
+ SCS2.getToType(1)->isCXX23FloatingPointType(S.Context) &&
+ S.Context.isCXX23EqualFloatingPointRank(
+ S.Context.getFloatingTypeOrder(SCS2.getToType(1),
+ SCS2.getFromType()))) {
+ if (SCS1.getToType(1)->isArithmeticType()) {
+ if (!SCS1.getToType(1)->isCXX23FloatingPointType(S.Context)) {
+ return ImplicitConversionSequence::Worse;
+ }
+
+ if (!S.Context.isCXX23EqualFloatingPointRank(
+ S.Context.getFloatingTypeOrder(SCS1.getToType(1),
+ SCS2.getFromType()))) {
+ return ImplicitConversionSequence::Worse;
+ }
+
+ if (S.Context.getFloatingTypeOrder(SCS2.getToType(1),
+ SCS1.getToType(1)) ==
+ FRCR_Equal_Greater_Subrank) {
+ return ImplicitConversionSequence::Worse;
+ }
+
+ assert(false && "Should not reach here");
+ }
+ }
+ }
+ }
+
// C++ [over.ics.rank]p4b2:
//
// If class B is derived directly or indirectly from class A,
@@ -8571,7 +8648,7 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
// Flag if we encounter an arithmetic type.
HasArithmeticOrEnumeralTypes =
- HasArithmeticOrEnumeralTypes || Ty->isArithmeticType();
+ HasArithmeticOrEnumeralTypes || Ty->isArithmeticType();
if (Ty->isObjCIdType() || Ty->isObjCClassType())
PointerTypes.insert(Ty);
diff --git a/clang/test/CodeGenCXX/cxx23-fp-ext-std-names-p1467r9.cpp b/clang/test/CodeGenCXX/cxx23-fp-ext-std-names-p1467r9.cpp
new file mode 100644
index 00000000000000..736948b5efb7b7
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx23-fp-ext-std-names-p1467r9.cpp
@@ -0,0 +1,499 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature
+// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -target-feature +fullbf16 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
+
+// CHECK-LABEL: define {{[^@]+}}@_Z1fDF16b
+// CHECK-SAME: (bfloat noundef [[V:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK: [[V_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: store bfloat [[V]], ptr [[V_ADDR]], align 2
+// CHECK-NEXT: ret i32 1
+//
+int f(decltype(0.BF16) v) { return 1; }
+// CHECK-LABEL: define {{[^@]+}}@_Z1fDF16_
+// CHECK-SAME: (half noundef [[V:%.*]]) #[[ATTR0]] {
+// CHECK: [[V_ADDR:%.*]] = alloca half, align 2
+// CHECK-NEXT: store half [[V]], ptr [[V_ADDR]], align 2
+// CHECK-NEXT: ret i32 1
+//
+int f(_Float16 v) { return 1; }
+// CHECK-LABEL: define {{[^@]+}}@_Z1ff
+// CHECK-SAME: (float noundef [[V:%.*]]) #[[ATTR0]] {
+// CHECK: [[V_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float [[V]], ptr [[V_ADDR]], align 4
+// CHECK-NEXT: ret i32 1
+//
+int f(float v) { return 1; }
+// CHECK-LABEL: define {{[^@]+}}@_Z1fd
+// CHECK-SAME: (double noundef [[V:%.*]]) #[[ATTR0]] {
+// CHECK: [[V_ADDR:%.*]] = alloca double, align 8
+// CHECK-NEXT: store double [[V]], ptr [[V_ADDR]], align 8
+// CHECK-NEXT: ret i32 1
+//
+int f(double v) { return 1; }
+// CHECK-LABEL: define {{[^@]+}}@_Z1fe
+// CHECK-SAME: (x86_fp80 noundef [[V:%.*]]) #[[ATTR0]] {
+// CHECK: [[V_ADDR:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: store x86_fp80 [[V]], ptr [[V_ADDR]], align 16
+// CHECK-NEXT: ret i32 1
+//
+int f(long double v) { return 1; }
+// CHECK-LABEL: define {{[^@]+}}@_Z1fi
+// CHECK-SAME: (i32 noundef [[V:%.*]]) #[[ATTR0]] {
+// CHECK: [[V_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[V]], ptr [[V_ADDR]], align 4
+// CHECK-NEXT: ret i32 1
+//
+int f(int v) { return 1; }
+
+// CHECK-LABEL: define {{[^@]+}}@_Z3f_2e
+// CHECK-SAME: (x86_fp80 noundef [[V:%.*]]) #[[ATTR0]] {
+// CHECK: [[V_ADDR:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: store x86_fp80 [[V]], ptr [[V_ADDR]], align 16
+// CHECK-NEXT: ret i32 1
+//
+int f_2(long double v) { return 1; }
+
+struct S {
+
+ operator decltype(0.BF16)() const {
+ return 0.0bf16;
+ }
+
+ operator _Float16() const {
+ return 0.0f16;
+ }
+
+ operator float() const {
+ return 0.0f;
+ }
+
+ operator double() const {
+ return 0.0;
+ }
+
+ operator long double() const {
+ return 0.0L;
+ }
+
+ operator int() const {
+ return 0;
+ }
+};
+
+struct S1 {
+ operator _Float16() const {
+ return 0.0f16;
+ }
+ operator float() const {
+ return 0.0f;
+ }
+ operator double() const {
+ return 0.0;
+ }
+ operator long double() const {
+ return 0.0L;
+ }
+
+ operator int() const {
+ return 0;
+ }
+};
+
+// CHECK-LABEL: define {{[^@]+}}@_Z5test1v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[F16_VAL_6:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[F16_VAL_8:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[F16_VAL_9:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[F16_VAL_10:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[F16_VAL_11:%.*]] = alloca half, align 2
+// CHECK-NEXT: store half 0xH3C00, ptr [[F16_VAL_6]], align 2
+// CHECK-NEXT: store half 0xH3C00, ptr [[F16_VAL_8]], align 2
+// CHECK-NEXT: store half 0xH3C00, ptr [[F16_VAL_9]], align 2
+// CHECK-NEXT: store half 0xH3C00, ptr [[F16_VAL_10]], align 2
+// CHECK-NEXT: store half 0xH3C00, ptr [[F16_VAL_11]], align 2
+// CHECK-NEXT: ret void
+//
+void test1() {
+ _Float16 f16_val_6 = 1.0f16;
+ _Float16 f16_val_8 = static_cast<_Float16>(1.0f);
+ _Float16 f16_val_9 = static_cast<_Float16>(1.0);
+ _Float16 f16_val_10 = static_cast<_Float16>(1.0l);
+ _Float16 f16_val_11 = static_cast<_Float16>(1.0f16);
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z5test2v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[BF16_VAL_5:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[BF16_VAL_7:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[BF16_VAL_8:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[BF16_VAL_9:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[BF16_VAL_10:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: store bfloat 0xR3F80, ptr [[BF16_VAL_5]], align 2
+// CHECK-NEXT: store bfloat 0xR3F80, ptr [[BF16_VAL_7]], align 2
+// CHECK-NEXT: store bfloat 0xR3F80, ptr [[BF16_VAL_8]], align 2
+// CHECK-NEXT: store bfloat 0xR3F80, ptr [[BF16_VAL_9]], align 2
+// CHECK-NEXT: store bfloat 0xR3F80, ptr [[BF16_VAL_10]], align 2
+// CHECK-NEXT: ret void
+//
+void test2() {
+ decltype(0.BF16) bf16_val_5 = 1.0bf16;
+ decltype(0.BF16) bf16_val_7 = static_cast<decltype(0.BF16)>(1.0f);
+ decltype(0.BF16) bf16_val_8 = static_cast<decltype(0.BF16)>(1.0);
+ decltype(0.BF16) bf16_val_9 = static_cast<decltype(0.BF16)>(1.0l);
+ decltype(0.BF16) bf16_val_10 = static_cast<decltype(0.BF16)>(1.0bf16);
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z5test3v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[F_VAL_1:%.*]] = alloca float, align 4
+// CHECK-NEXT: [[F_VAL_2:%.*]] = alloca float, align 4
+// CHECK-NEXT: [[F_VAL_3:%.*]] = alloca float, align 4
+// CHECK-NEXT: [[F_VAL_4:%.*]] = alloca float, align 4
+// CHECK-NEXT: [[F_VAL_5:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float 1.000000e+00, ptr [[F_VAL_1]], align 4
+// CHECK-NEXT: store float 1.000000e+00, ptr [[F_VAL_2]], align 4
+// CHECK-NEXT: store float 1.000000e+00, ptr [[F_VAL_3]], align 4
+// CHECK-NEXT: store float 1.000000e+00, ptr [[F_VAL_4]], align 4
+// CHECK-NEXT: store float 1.000000e+00, ptr [[F_VAL_5]], align 4
+// CHECK-NEXT: ret void
+//
+void test3() {
+ float f_val_1 = 1.0f16;
+ float f_val_2 = 1.0bf16;
+ float f_val_3 = 1.0;
+ float f_val_4 = 1.0l;
+ float f_val_5 = 1.0f;
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z5test4v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[D_VAL_1:%.*]] = alloca double, align 8
+// CHECK-NEXT: [[D_VAL_2:%.*]] = alloca double, align 8
+// CHECK-NEXT: [[D_VAL_3:%.*]] = alloca double, align 8
+// CHECK-NEXT: [[D_VAL_4:%.*]] = alloca double, align 8
+// CHECK-NEXT: [[D_VAL_5:%.*]] = alloca double, align 8
+// CHECK-NEXT: store double 1.000000e+00, ptr [[D_VAL_1]], align 8
+// CHECK-NEXT: store double 1.000000e+00, ptr [[D_VAL_2]], align 8
+// CHECK-NEXT: store double 1.000000e+00, ptr [[D_VAL_3]], align 8
+// CHECK-NEXT: store double 1.000000e+00, ptr [[D_VAL_4]], align 8
+// CHECK-NEXT: store double 1.000000e+00, ptr [[D_VAL_5]], align 8
+// CHECK-NEXT: ret void
+//
+void test4() {
+ double d_val_1 = 1.0f16;
+ double d_val_2 = 1.0bf16;
+ double d_val_3 = 1.0f;
+ double d_val_4 = 1.0l;
+ double d_val_5 = 1.0;
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z5test5v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[LD_VAL_1:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: [[LD_VAL_2:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: [[LD_VAL_3:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: [[LD_VAL_4:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: [[LD_VAL_5:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: store x86_fp80 0xK3FFF8000000000000000, ptr [[LD_VAL_1]], align 16
+// CHECK-NEXT: store x86_fp80 0xK3FFF8000000000000000, ptr [[LD_VAL_2]], align 16
+// CHECK-NEXT: store x86_fp80 0xK3FFF8000000000000000, ptr [[LD_VAL_3]], align 16
+// CHECK-NEXT: store x86_fp80 0xK3FFF8000000000000000, ptr [[LD_VAL_4]], align 16
+// CHECK-NEXT: store x86_fp80 0xK3FFF8000000000000000, ptr [[LD_VAL_5]], align 16
+// CHECK-NEXT: ret void
+//
+void test5() {
+ long double ld_val_1 = 1.0f16;
+ long double ld_val_2 = 1.0bf16;
+ long double ld_val_3 = 1.0f;
+ long double ld_val_4 = 1.0;
+ long double ld_val_5 = 1.0l;
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z5test6v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[F16_FLOAT:%.*]] = alloca float, align 4
+// CHECK-NEXT: [[F16_DOUBLE:%.*]] = alloca double, align 8
+// CHECK-NEXT: [[F16_LDOUBLE:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: [[F16_INT:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[F16_UINT:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[F16_LONG:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[F16_ULONG:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[F16_LLONG:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[F16_ULLONG:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[F16_BOOL:%.*]] = alloca half, align 2
+// CHECK-NEXT: store float 2.000000e+00, ptr [[F16_FLOAT]], align 4
+// CHECK-NEXT: store double 2.000000e+00, ptr [[F16_DOUBLE]], align 8
+// CHECK-NEXT: store x86_fp80 0xK40008000000000000000, ptr [[F16_LDOUBLE]], align 16
+// CHECK-NEXT: store half 0xH4000, ptr [[F16_INT]], align 2
+// CHECK-NEXT: store half 0xH4000, ptr [[F16_UINT]], align 2
+// CHECK-NEXT: store half 0xH4000, ptr [[F16_LONG]], align 2
+// CHECK-NEXT: store half 0xH4000, ptr [[F16_ULONG]], align 2
+// CHECK-NEXT: store half 0xH4000, ptr [[F16_LLONG]], align 2
+// CHECK-NEXT: store half 0xH4000, ptr [[F16_ULLONG]], align 2
+// CHECK-NEXT: store half 0xH4000, ptr [[F16_BOOL]], align 2
+// CHECK-NEXT: ret void
+//
+void test6() {
+ auto f16_float = 1.0f16 + 1.0f;
+ auto f16_double = 1.0f16 + 1.0;
+ auto f16_ldouble = 1.0f16 + 1.0l;
+ auto f16_int = 1.0f16 + 1;
+ auto f16_uint = 1.0f16 + 1u;
+ auto f16_long = 1.0f16 + 1l;
+ auto f16_ulong = 1.0f16 + 1ul;
+ auto f16_llong = 1.0f16 + 1ll;
+ auto f16_ullong = 1.0f16 + 1ull;
+ auto f16_bool = 1.0f16 + true;
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z5test7v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[BF16_FLOAT:%.*]] = alloca float, align 4
+// CHECK-NEXT: [[BF16_DOUBLE:%.*]] = alloca double, align 8
+// CHECK-NEXT: [[BF16_LDOUBLE:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: [[BF16_INT:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[BF16_UINT:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[BF16_LONG:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[BF16_ULONG:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[BF16_LLONG:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[BF16_ULLONG:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[BF16_BOOL:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: store float 2.000000e+00, ptr [[BF16_FLOAT]], align 4
+// CHECK-NEXT: store double 2.000000e+00, ptr [[BF16_DOUBLE]], align 8
+// CHECK-NEXT: store x86_fp80 0xK40008000000000000000, ptr [[BF16_LDOUBLE]], align 16
+// CHECK-NEXT: store bfloat 0xR4000, ptr [[BF16_INT]], align 2
+// CHECK-NEXT: store bfloat 0xR4000, ptr [[BF16_UINT]], align 2
+// CHECK-NEXT: store bfloat 0xR4000, ptr [[BF16_LONG]], align 2
+// CHECK-NEXT: store bfloat 0xR4000, ptr [[BF16_ULONG]], align 2
+// CHECK-NEXT: store bfloat 0xR4000, ptr [[BF16_LLONG]], align 2
+// CHECK-NEXT: store bfloat 0xR4000, ptr [[BF16_ULLONG]], align 2
+// CHECK-NEXT: store bfloat 0xR4000, ptr [[BF16_BOOL]], align 2
+// CHECK-NEXT: ret void
+//
+void test7() {
+ auto bf16_float = 1.0bf16 + 1.0f;
+ //
+ auto bf16_double = 1.0bf16 + 1.0;
+ auto bf16_ldouble = 1.0bf16 + 1.0l;
+ auto bf16_int = 1.0bf16 + 1;
+ auto bf16_uint = 1.0bf16 + 1u;
+ auto bf16_long = 1.0bf16 + 1l;
+ auto bf16_ulong = 1.0bf16 + 1ul;
+ auto bf16_llong = 1.0bf16 + 1ll;
+ auto bf16_ullong = 1.0bf16 + 1ull;
+ auto bf16_bool = 1.0bf16 + true;
+}
+
+//
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test8_1v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[BF16_VAL:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[TEST1:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[TEST_9:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store bfloat 0xR3F80, ptr [[BF16_VAL]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[BF16_VAL]], align 2
+// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_Z1fDF16b(bfloat noundef [[TMP0]])
+// CHECK-NEXT: store i32 [[CALL]], ptr [[TEST1]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[BF16_VAL]], align 2
+// CHECK-NEXT: [[CONV:%.*]] = fpext bfloat [[TMP1]] to x86_fp80
+// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_Z3f_2e(x86_fp80 noundef [[CONV]])
+// CHECK-NEXT: store i32 [[CALL1]], ptr [[TEST_9]], align 4
+// CHECK-NEXT: ret void
+//
+void test8_1() {
+ decltype(0.BF16) bf16_val = 1.0bf16;
+ int test1 = f(bf16_val); // calls f(decltype(0.BF16))
+ int test_9 = f_2(bf16_val);
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test8_2v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[FLOAT16_VAL:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[TEST2:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[TEST_10:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store half 0xH3C00, ptr [[FLOAT16_VAL]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = load half, ptr [[FLOAT16_VAL]], align 2
+// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_Z1fDF16_(half noundef [[TMP0]])
+// CHECK-NEXT: store i32 [[CALL]], ptr [[TEST2]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load half, ptr [[FLOAT16_VAL]], align 2
+// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP1]] to x86_fp80
+// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_Z3f_2e(x86_fp80 noundef [[CONV]])
+// CHECK-NEXT: store i32 [[CALL1]], ptr [[TEST_10]], align 4
+// CHECK-NEXT: ret void
+//
+void test8_2() {
+ _Float16 float16_val = 1.0f16;
+ int test2 = f(float16_val); // calls f(_Float16)
+ int test_10 = f_2(float16_val);
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test8_3v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[FLOAT_VAL:%.*]] = alloca float, align 4
+// CHECK-NEXT: [[TEST3:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[TEST_7:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store float 1.000000e+00, ptr [[FLOAT_VAL]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[FLOAT_VAL]], align 4
+// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_Z1ff(float noundef [[TMP0]])
+// CHECK-NEXT: store i32 [[CALL]], ptr [[TEST3]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[FLOAT_VAL]], align 4
+// CHECK-NEXT: [[CONV:%.*]] = fpext float [[TMP1]] to x86_fp80
+// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_Z3f_2e(x86_fp80 noundef [[CONV]])
+// CHECK-NEXT: store i32 [[CALL1]], ptr [[TEST_7]], align 4
+// CHECK-NEXT: ret void
+//
+void test8_3() {
+ float float_val = 1.0f;
+ int test3 = f(float_val); // calls f(float)
+ int test_7 = f_2(float_val);
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test8_4v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[DOUBLE_VAL:%.*]] = alloca double, align 8
+// CHECK-NEXT: [[TEST4:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[TEST_8:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store double 1.000000e+00, ptr [[DOUBLE_VAL]], align 8
+// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[DOUBLE_VAL]], align 8
+// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_Z1fd(double noundef [[TMP0]])
+// CHECK-NEXT: store i32 [[CALL]], ptr [[TEST4]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load double, ptr [[DOUBLE_VAL]], align 8
+// CHECK-NEXT: [[CONV:%.*]] = fpext double [[TMP1]] to x86_fp80
+// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_Z3f_2e(x86_fp80 noundef [[CONV]])
+// CHECK-NEXT: store i32 [[CALL1]], ptr [[TEST_8]], align 4
+// CHECK-NEXT: ret void
+//
+void test8_4() {
+ double double_val = 1.0;
+ int test4 = f(double_val); // calls f(double)
+ int test_8 = f_2(double_val);
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test8_5v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[LONG_DOUBLE_VAL:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: [[TEST5:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store x86_fp80 0xK3FFF8000000000000000, ptr [[LONG_DOUBLE_VAL]], align 16
+// CHECK-NEXT: [[TMP0:%.*]] = load x86_fp80, ptr [[LONG_DOUBLE_VAL]], align 16
+// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_Z1fe(x86_fp80 noundef [[TMP0]])
+// CHECK-NEXT: store i32 [[CALL]], ptr [[TEST5]], align 4
+// CHECK-NEXT: ret void
+//
+void test8_5() {
+ long double long_double_val = 1.0l;
+ int test5 = f(long_double_val); // calls f(long double)
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test8_6v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[INT_VAL:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[TEST6:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 1, ptr [[INT_VAL]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[INT_VAL]], align 4
+// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_Z1fi(i32 noundef [[TMP0]])
+// CHECK-NEXT: store i32 [[CALL]], ptr [[TEST6]], align 4
+// CHECK-NEXT: ret void
+//
+void test8_6() {
+ int int_val = 1;
+ int test6 = f(int_val); // calls f(int)
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test9_1v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[USER_DEFINED_VAL:%.*]] = alloca [[STRUCT_S:%.*]], align 1
+// CHECK-NEXT: [[BFLOAT16_VAL:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[CALL:%.*]] = call noundef bfloat @_ZNK1ScvDF16bEv(ptr noundef nonnull align 1 dereferenceable(1) [[USER_DEFINED_VAL]])
+// CHECK-NEXT: store bfloat [[CALL]], ptr [[BFLOAT16_VAL]], align 2
+// CHECK-NEXT: ret void
+//
+void test9_1() {
+ S user_defined_val;
+ // User-defined overload cases
+ decltype(0.BF16) bfloat16_val(user_defined_val); // calls operator decltype(0.BF16)()
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test9_2v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[USER_DEFINED_VAL:%.*]] = alloca [[STRUCT_S:%.*]], align 1
+// CHECK-NEXT: [[F16_VAL:%.*]] = alloca half, align 2
+// CHECK-NEXT: [[CALL:%.*]] = call noundef half @_ZNK1ScvDF16_Ev(ptr noundef nonnull align 1 dereferenceable(1) [[USER_DEFINED_VAL]])
+// CHECK-NEXT: store half [[CALL]], ptr [[F16_VAL]], align 2
+// CHECK-NEXT: ret void
+//
+void test9_2() {
+ S user_defined_val;
+ // User-defined overload cases
+ _Float16 f16_val(user_defined_val); // calls operator _Float16()
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test9_3v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[USER_DEFINED_VAL:%.*]] = alloca [[STRUCT_S:%.*]], align 1
+// CHECK-NEXT: [[F_VAL:%.*]] = alloca float, align 4
+// CHECK-NEXT: [[CALL:%.*]] = call noundef float @_ZNK1ScvfEv(ptr noundef nonnull align 1 dereferenceable(1) [[USER_DEFINED_VAL]])
+// CHECK-NEXT: store float [[CALL]], ptr [[F_VAL]], align 4
+// CHECK-NEXT: ret void
+//
+void test9_3() {
+ S user_defined_val;
+ // User-defined overload cases
+ float f_val(user_defined_val); // calls operator float()
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test9_4v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[USER_DEFINED_VAL:%.*]] = alloca [[STRUCT_S:%.*]], align 1
+// CHECK-NEXT: [[D_VAL:%.*]] = alloca double, align 8
+// CHECK-NEXT: [[CALL:%.*]] = call noundef double @_ZNK1ScvdEv(ptr noundef nonnull align 1 dereferenceable(1) [[USER_DEFINED_VAL]])
+// CHECK-NEXT: store double [[CALL]], ptr [[D_VAL]], align 8
+// CHECK-NEXT: ret void
+//
+void test9_4() {
+ S user_defined_val;
+ // User-defined overload cases
+ double d_val(user_defined_val); // calls operator double()
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test9_5v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[USER_DEFINED_VAL:%.*]] = alloca [[STRUCT_S:%.*]], align 1
+// CHECK-NEXT: [[LD_VAL:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: [[CALL:%.*]] = call noundef x86_fp80 @_ZNK1ScveEv(ptr noundef nonnull align 1 dereferenceable(1) [[USER_DEFINED_VAL]])
+// CHECK-NEXT: store x86_fp80 [[CALL]], ptr [[LD_VAL]], align 16
+// CHECK-NEXT: ret void
+//
+void test9_5() {
+ S user_defined_val;
+ // User-defined overload cases
+ long double ld_val(user_defined_val); // calls operator long double()
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test9_6v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[USER_DEFINED_VAL:%.*]] = alloca [[STRUCT_S:%.*]], align 1
+// CHECK-NEXT: [[I_VAL:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZNK1ScviEv(ptr noundef nonnull align 1 dereferenceable(1) [[USER_DEFINED_VAL]])
+// CHECK-NEXT: store i32 [[CALL]], ptr [[I_VAL]], align 4
+// CHECK-NEXT: ret void
+//
+void test9_6() {
+ S user_defined_val;
+ // User-defined overload cases
+ int i_val(user_defined_val); // calls operator int()
+}
+
+// CHECK-LABEL: define {{[^@]+}}@_Z7test9_7v
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK: [[USER_DEFINED_VAL_2:%.*]] = alloca [[STRUCT_S1:%.*]], align 1
+// CHECK-NEXT: [[BFLOAT16_VAL_2:%.*]] = alloca bfloat, align 2
+// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZNK2S1cviEv(ptr noundef nonnull align 1 dereferenceable(1) [[USER_DEFINED_VAL_2]])
+// CHECK-NEXT: [[CONV:%.*]] = sitofp i32 [[CALL]] to bfloat
+// CHECK-NEXT: store bfloat [[CONV]], ptr [[BFLOAT16_VAL_2]], align 2
+// CHECK-NEXT: ret void
+//
+void test9_7() {
+ S1 user_defined_val_2;
+ // User-defined overload cases
+ decltype(0.BF16) bfloat16_val_2(user_defined_val_2); // calls operator int()
+}
diff --git a/clang/test/CodeGenCXX/cxx23-vector-bfloat16.cpp b/clang/test/CodeGenCXX/cxx23-vector-bfloat16.cpp
new file mode 100644
index 00000000000000..8bccddbd3cf083
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx23-vector-bfloat16.cpp
@@ -0,0 +1,67 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
+// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -target-feature +fullbf16 -S -emit-llvm %s -o - | FileCheck %s
+
+typedef decltype(0.0BF16) v8bfloat16 __attribute__((__vector_size__(16)));
+
+// CHECK-LABEL: define dso_local void @_Z11test_vectorDv8_DF16bS_
+// CHECK-SAME: (<8 x bfloat> noundef [[A:%.*]], <8 x bfloat> noundef [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK: [[A_ADDR:%.*]] = alloca <8 x bfloat>, align 16
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <8 x bfloat>, align 16
+// CHECK-NEXT: [[C:%.*]] = alloca <8 x bfloat>, align 16
+// CHECK-NEXT: store <8 x bfloat> [[A]], ptr [[A_ADDR]], align 16
+// CHECK-NEXT: store <8 x bfloat> [[B]], ptr [[B_ADDR]], align 16
+// CHECK-NEXT: [[TMP0:%.*]] = load <8 x bfloat>, ptr [[A_ADDR]], align 16
+// CHECK-NEXT: [[TMP1:%.*]] = load <8 x bfloat>, ptr [[B_ADDR]], align 16
+// CHECK-NEXT: [[ADD:%.*]] = fadd <8 x bfloat> [[TMP0]], [[TMP1]]
+// CHECK-NEXT: store <8 x bfloat> [[ADD]], ptr [[C]], align 16
+// CHECK-NEXT: [[TMP2:%.*]] = load <8 x bfloat>, ptr [[A_ADDR]], align 16
+// CHECK-NEXT: [[TMP3:%.*]] = load <8 x bfloat>, ptr [[B_ADDR]], align 16
+// CHECK-NEXT: [[SUB:%.*]] = fsub <8 x bfloat> [[TMP2]], [[TMP3]]
+// CHECK-NEXT: store <8 x bfloat> [[SUB]], ptr [[C]], align 16
+// CHECK-NEXT: [[TMP4:%.*]] = load <8 x bfloat>, ptr [[A_ADDR]], align 16
+// CHECK-NEXT: [[TMP5:%.*]] = load <8 x bfloat>, ptr [[B_ADDR]], align 16
+// CHECK-NEXT: [[MUL:%.*]] = fmul <8 x bfloat> [[TMP4]], [[TMP5]]
+// CHECK-NEXT: store <8 x bfloat> [[MUL]], ptr [[C]], align 16
+// CHECK-NEXT: [[TMP6:%.*]] = load <8 x bfloat>, ptr [[A_ADDR]], align 16
+// CHECK-NEXT: [[TMP7:%.*]] = load <8 x bfloat>, ptr [[B_ADDR]], align 16
+// CHECK-NEXT: [[DIV:%.*]] = fdiv <8 x bfloat> [[TMP6]], [[TMP7]]
+// CHECK-NEXT: store <8 x bfloat> [[DIV]], ptr [[C]], align 16
+// CHECK-NEXT: ret void
+//
+void test_vector(v8bfloat16 a, v8bfloat16 b) {
+ v8bfloat16 c;
+ c = a + b;
+ c = a - b;
+ c = a * b;
+ c = a / b;
+}
+
+// CHECK-LABEL: define dso_local void @_Z13test_vector_2v
+// CHECK-SAME: () #[[ATTR1:[0-9]+]] {
+// CHECK: [[A:%.*]] = alloca <8 x bfloat>, align 16
+// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca <8 x bfloat>, align 16
+// CHECK-NEXT: [[B:%.*]] = alloca <8 x bfloat>, align 16
+// CHECK-NEXT: [[DOTCOMPOUNDLITERAL1:%.*]] = alloca <8 x bfloat>, align 16
+// CHECK-NEXT: [[C:%.*]] = alloca <8 x bfloat>, align 16
+// CHECK-NEXT: [[D:%.*]] = alloca <8 x bfloat>, align 16
+// CHECK-NEXT: store <8 x bfloat> zeroinitializer, ptr [[DOTCOMPOUNDLITERAL]], align 16
+// CHECK-NEXT: [[TMP0:%.*]] = load <8 x bfloat>, ptr [[DOTCOMPOUNDLITERAL]], align 16
+// CHECK-NEXT: store <8 x bfloat> [[TMP0]], ptr [[A]], align 16
+// CHECK-NEXT: store <8 x bfloat> <bfloat 0xR3F80, bfloat 0xR0000, bfloat 0xR0000, bfloat 0xR0000, bfloat 0xR0000, bfloat 0xR0000, bfloat 0xR0000, bfloat 0xR0000>, ptr [[DOTCOMPOUNDLITERAL1]], align 16
+// CHECK-NEXT: [[TMP1:%.*]] = load <8 x bfloat>, ptr [[DOTCOMPOUNDLITERAL1]], align 16
+// CHECK-NEXT: store <8 x bfloat> [[TMP1]], ptr [[B]], align 16
+// CHECK-NEXT: [[TMP2:%.*]] = load <8 x bfloat>, ptr [[A]], align 16
+// CHECK-NEXT: [[ELT_ABS:%.*]] = call <8 x bfloat> @llvm.fabs.v8bf16(<8 x bfloat> [[TMP2]])
+// CHECK-NEXT: store <8 x bfloat> [[ELT_ABS]], ptr [[C]], align 16
+// CHECK-NEXT: [[TMP3:%.*]] = load <8 x bfloat>, ptr [[C]], align 16
+// CHECK-NEXT: [[ELT_ABS2:%.*]] = call <8 x bfloat> @llvm.fabs.v8bf16(<8 x bfloat> [[TMP3]])
+// CHECK-NEXT: store <8 x bfloat> [[ELT_ABS2]], ptr [[D]], align 16
+// CHECK-NEXT: ret void
+//
+void test_vector_2() {
+ v8bfloat16 a = (v8bfloat16){0.0bf16};
+ v8bfloat16 b = (v8bfloat16){1.0bf16};
+ v8bfloat16 c = __builtin_elementwise_abs(a);
+ v8bfloat16 d = __builtin_elementwise_abs(c);
+}
+
diff --git a/clang/test/Sema/cxx23-fp-ext-std-names-p1467r9.cpp b/clang/test/Sema/cxx23-fp-ext-std-names-p1467r9.cpp
new file mode 100644
index 00000000000000..23ac2d21d80777
--- /dev/null
+++ b/clang/test/Sema/cxx23-fp-ext-std-names-p1467r9.cpp
@@ -0,0 +1,505 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 -target-feature +fullbf16 -verify -ast-dump %s | FileCheck %s
+#include <stdarg.h>
+_Float16 f16_val_1 = 1.0bf16; // expected-error {{cannot initialize a variable of type '_Float16' with an rvalue of type '__bf16'}}
+_Float16 f16_val_2 = 1.0f; // expected-error {{cannot initialize a variable of type '_Float16' with an rvalue of type 'float'}}
+_Float16 f16_val_3 = 1.0; // expected-error {{cannot initialize a variable of type '_Float16' with an rvalue of type 'double'}}
+_Float16 f16_val_4 = 1.0l; // expected-error {{cannot initialize a variable of type '_Float16' with an rvalue of type 'long double'}}
+_Float16 f16_val_6 = 1.0f16;
+//CHECK: VarDecl {{.*}} f16_val_6 '_Float16' cinit
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+_Float16 f16_val_7 = static_cast<_Float16>(1.0bf16); // expected-error {{static_cast from '__bf16' to '_Float16' is not allowed}}
+_Float16 f16_val_8 = static_cast<_Float16>(1.0f);
+//CHECK: VarDecl {{.*}} f16_val_8 '_Float16' cinit
+//CHECK-NEXT: CXXStaticCastExpr {{.*}} '_Float16' static_cast<_Float16> <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+_Float16 f16_val_9 = static_cast<_Float16>(1.0);
+//CHECK: VarDecl {{.*}} f16_val_9 '_Float16' cinit
+//CHECK-NEXT: CXXStaticCastExpr {{.*}} '_Float16' static_cast<_Float16> <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
+_Float16 f16_val_10 = static_cast<_Float16>(1.0l);
+//CHECK: VarDecl {{.*}} f16_val_10 '_Float16' cinit
+//CHECK-NEXT: CXXStaticCastExpr {{.*}} '_Float16' static_cast<_Float16> <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'long double' 1.000000e+00
+_Float16 f16_val_11 = static_cast<_Float16>(1.0f16);
+//CHECK: VarDecl {{.*}} f16_val_11 '_Float16' cinit
+//CHECK-NEXT: CXXStaticCastExpr {{.*}} '_Float16' static_cast<_Float16> <NoOp>
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+
+decltype(0.0BF16) bf16_val_1 = 1.0f16; // expected-error {{cannot initialize a variable of type 'decltype(0.BF16)' (aka '__bf16') with an rvalue of type '_Float16'}}
+decltype(0.0BF16) bf16_val_2 = 1.0f; // expected-error {{cannot initialize a variable of type 'decltype(0.BF16)' (aka '__bf16') with an rvalue of type 'float'}}
+decltype(0.0BF16) bf16_val_3 = 1.0; // expected-error {{cannot initialize a variable of type 'decltype(0.BF16)' (aka '__bf16') with an rvalue of type 'double'}}
+decltype(0.0BF16) bf16_val_4 = 1.0l; // expected-error {{cannot initialize a variable of type 'decltype(0.BF16)' (aka '__bf16') with an rvalue of type 'long double'}}
+decltype(0.0BF16) bf16_val_5 = 1.0bf16;
+//CHECK: VarDecl {{.*}} bf16_val_5 'decltype(0.BF16)':'__bf16' cinit
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+
+decltype(0.0BF16) bf16_val_6 = static_cast<decltype(0.0BF16)>(1.0f16); // expected-error {{static_cast from '_Float16' to 'decltype(0.BF16)' (aka '__bf16') is not allowed}}
+decltype(0.0BF16) bf16_val_7 = static_cast<decltype(0.0BF16)>(1.0f);
+//CHECK: VarDecl {{.*}} bf16_val_7 'decltype(0.BF16)':'__bf16' cinit
+//CHECK-NEXT: CXXStaticCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' static_cast<decltype(0.BF16)> <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+decltype(0.0BF16) bf16_val_8 = static_cast<decltype(0.0BF16)>(1.0);
+//CHECK: VarDecl {{.*}} bf16_val_8 'decltype(0.BF16)':'__bf16' cinit
+//CHECK-NEXT: CXXStaticCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' static_cast<decltype(0.BF16)> <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
+decltype(0.0BF16) bf16_val_9 = static_cast<decltype(0.0BF16)>(1.0l);
+//CHECK: VarDecl {{.*}} bf16_val_9 'decltype(0.BF16)':'__bf16' cinit
+//CHECK-NEXT: CXXStaticCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' static_cast<decltype(0.BF16)> <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'long double' 1.000000e+00
+decltype(0.0BF16) bf16_val_10 = static_cast<decltype(0.0BF16)>(1.0bf16);
+//CHECK: VarDecl {{.*}} bf16_val_10 'decltype(0.BF16)':'__bf16' cinit
+//CHECK-NEXT: CXXStaticCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' static_cast<decltype(0.BF16)> <NoOp>
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+
+float f_val_1 = 1.0f16;
+//CHECK: VarDecl {{.*}} f_val_1 'float' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+float f_val_2 = 1.0bf16;
+//CHECK: VarDecl {{.*}} f_val_2 'float' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+float f_val_3 = 1.0;
+//CHECK: VarDecl {{.*}} f_val_3 'float' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
+float f_val_4 = 1.0l;
+//CHECK: VarDecl {{.*}} f_val_4 'float' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'long double' 1.000000e+00
+float f_val_5 = 1.0f;
+//CHECK: VarDecl {{.*}} f_val_5 'float' cinit
+//CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+
+double d_val_1 = 1.0f16;
+//CHECK: VarDecl {{.*}} d_val_1 'double' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+double d_val_2 = 1.0bf16;
+//CHECK: VarDecl {{.*}} d_val_2 'double' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+double d_val_3 = 1.0f;
+//CHECK: VarDecl {{.*}} d_val_3 'double' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+double d_val_4 = 1.0l;
+//CHECK: VarDecl {{.*}} d_val_4 'double' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'long double' 1.000000e+00
+double d_val_5 = 1.0;
+//CHECK: VarDecl {{.*}} d_val_5 'double' cinit
+//CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
+
+long double ld_val_1 = 1.0f16;
+//CHECK: VarDecl {{.*}} ld_val_1 'long double' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+long double ld_val_2 = 1.0bf16;
+//CHECK: VarDecl {{.*}} ld_val_2 'long double' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+long double ld_val_3 = 1.0f;
+//CHECK: VarDecl {{.*}} ld_val_3 'long double' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+long double ld_val_4 = 1.0;
+//CHECK: VarDecl {{.*}} ld_val_4 'long double' cinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
+long double ld_val_5 = 1.0l;
+//CHECK: VarDecl {{.*}} ld_val_5 'long double' cinit
+//CHECK-NEXT: FloatingLiteral {{.*}} 'long double' 1.000000e+00
+
+auto f16_bf16 = 1.0f16 + 1.0bf16; // expected-error {{invalid operands to binary expression ('_Float16' and '__bf16')}}
+auto f16_bf16_cast = 1.0f16 + static_cast<_Float16>(1.0bf16); // expected-error {{static_cast from '__bf16' to '_Float16' is not allowed}}
+auto f16_float = 1.0f16 + 1.0f;
+//CHECK: VarDecl {{.*}} f16_float 'float' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} 'float' '+'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+auto f16_double = 1.0f16 + 1.0;
+//CHECK: VarDecl {{.*}} f16_double 'double' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} 'double' '+'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
+auto f16_ldouble = 1.0f16 + 1.0l;
+//CHECK: VarDecl {{.*}} f16_ldouble 'long double' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} 'long double' '+'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: FloatingLiteral {{.*}} 'long double' 1.000000e+00
+auto f16_int = 1.0f16 + 1;
+//CHECK: VarDecl {{.*}} f16_int '_Float16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+auto f16_uint = 1.0f16 + 1u;
+//CHECK: VarDecl {{.*}} f16_uint '_Float16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1
+auto f16_long = 1.0f16 + 1l;
+//CHECK: VarDecl {{.*}} f16_long '_Float16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'long' 1
+auto f16_ulong = 1.0f16 + 1ul;
+//CHECK: VarDecl {{.*}} f16_ulong '_Float16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+auto f16_llong = 1.0f16 + 1ll;
+//CHECK: VarDecl {{.*}} f16_llong '_Float16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'long long' 1
+auto f16_ullong = 1.0f16 + 1ull;
+//CHECK: VarDecl {{.*}} f16_ullong '_Float16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long long' 1
+auto f16_bool = 1.0f16 + true;
+//CHECK: VarDecl {{.*}} f16_bool '_Float16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <IntegralToFloating>
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <IntegralCast>
+//CHECK-NEXT: CXXBoolLiteralExpr {{.*}} 'bool' true
+
+auto bf16_fp16 = 1.0bf16 + 1.0f16; // expected-error {{invalid operands to binary expression ('__bf16' and '_Float16')}}
+auto bf16_fp16_cast = 1.0bf16 + static_cast<decltype(0.0BF16)>(1.0f16); // expected-error {{static_cast from '_Float16' to 'decltype(0.BF16)' (aka '__bf16') is not allowed}}
+auto bf16_float = 1.0bf16 + 1.0f;
+//CHECK: VarDecl {{.*}} bf16_float 'float' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} 'float' '+'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+//CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+auto bf16_double = 1.0bf16 + 1.0;
+//CHECK: VarDecl {{.*}} bf16_double 'double' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} 'double' '+'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+//CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
+auto bf16_ldouble = 1.0bf16 + 1.0l;
+//CHECK: VarDecl {{.*}} bf16_ldouble 'long double' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} 'long double' '+'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+//CHECK-NEXT: FloatingLiteral {{.*}} 'long double' 1.000000e+00
+auto bf16_int = 1.0bf16 + 1;
+//CHECK: VarDecl {{.*}} bf16_int '__bf16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+auto bf16_uint = 1.0bf16 + 1u;
+//CHECK: VarDecl {{.*}} bf16_uint '__bf16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1
+auto bf16_long = 1.0bf16 + 1l;
+//CHECK: VarDecl {{.*}} bf16_long '__bf16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'long' 1
+auto bf16_ulong = 1.0bf16 + 1ul;
+//CHECK: VarDecl {{.*}} bf16_ulong '__bf16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+auto bf16_llong = 1.0bf16 + 1ll;
+//CHECK: VarDecl {{.*}} bf16_llong '__bf16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'long long' 1
+auto bf16_ullong = 1.0bf16 + 1ull;
+//CHECK: VarDecl {{.*}} bf16_ullong '__bf16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long long' 1
+auto bf16_bool = 1.0bf16 + true;
+//CHECK: VarDecl {{.*}} bf16_bool '__bf16' cinit
+//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+'
+//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' <IntegralToFloating>
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <IntegralCast>
+//CHECK-NEXT: CXXBoolLiteralExpr {{.*}} 'bool' true
+
+int f(decltype(0.0BF16)) {}
+int f(_Float16) {}
+int f(float) {}
+int f(double) {}
+int f(long double) {}
+int f(int) {}
+
+decltype(0.0BF16) bf16_val = 1.0bf16;
+_Float16 float16_val = 1.0f16;
+float float_val = 1.0f;
+double double_val = 1.0;
+long double long_double_val = 1.0l;
+int int_val = 1;
+
+int test1 = f(bf16_val); // calls f(decltype(0.BF16))
+//CHECK: VarDecl {{.*}} test1 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(decltype(0.BF16))' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (decltype(0.BF16))' lvalue Function {{.*}} 'f' 'int (decltype(0.BF16))'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'decltype(0.BF16)':'__bf16' lvalue Var {{.*}} 'bf16_val' 'decltype(0.BF16)':'__bf16'
+int test2 = f(float16_val); // calls f(_Float16)
+//CHECK: VarDecl {{.*}} test2 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(_Float16)' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (_Float16)' lvalue Function {{.*}} 'f' 'int (_Float16)'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'float16_val' '_Float16'
+int test3 = f(float_val); // calls f(float)
+//CHECK: VarDecl {{.*}} test3 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(float)' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (float)' lvalue Function {{.*}} 'f' 'int (float)'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue Var {{.*}} 'float_val' 'float'
+int test4 = f(double_val); // calls f(double)
+//CHECK: VarDecl {{.*}} test4 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(double)' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (double)' lvalue Function {{.*}} 'f' 'int (double)'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'double' lvalue Var {{.*}} 'double_val' 'double'
+int test5 = f(long_double_val); // calls f(long double)
+//CHECK: VarDecl {{.*}} test5 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(long double)' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (long double)' lvalue Function {{.*}} 'f' 'int (long double)'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'long double' lvalue Var {{.*}} 'long_double_val' 'long double'
+int test6 = f(int_val); // calls f(int)
+//CHECK: VarDecl {{.*}} test6 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(int)' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (int)' lvalue Function {{.*}} 'f' 'int (int)'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'int_val' 'int'
+
+int f_1(float) {} // expected-note {{candidate function}} expected-note {{candidate function}}
+int f_1(double) {} // expected-note {{candidate function}} expected-note {{candidate function}}
+
+// Ambiguous cases
+int test_7 = f_1(bf16_val); // expected-error {{call to 'f_1' is ambiguous}}
+int test_8 = f_1(float16_val); // expected-error {{call to 'f_1' is ambiguous}}
+
+int f_2(long double) {}
+int test_9 = f_2(float_val);
+//CHECK: VarDecl {{.*}} test_9 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(long double)' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (long double)' lvalue Function {{.*}} 'f_2' 'int (long double)'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue Var {{.*}} 'float_val' 'float'
+int test_10 = f_2(double_val);
+//CHECK: VarDecl {{.*}} test_10 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(long double)' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (long double)' lvalue Function {{.*}} 'f_2' 'int (long double)'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'double' lvalue Var {{.*}} 'double_val' 'double'
+int test_11 = f_2(bf16_val);
+//CHECK: VarDecl {{.*}} test_11 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(long double)' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (long double)' lvalue Function {{.*}} 'f_2' 'int (long double)'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'decltype(0.BF16)':'__bf16' lvalue Var {{.*}} 'bf16_val' 'decltype(0.BF16)':'__bf16'
+int test_12 = f_2(float16_val);
+//CHECK: VarDecl {{.*}} test_12 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(long double)' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (long double)' lvalue Function {{.*}} 'f_2' 'int (long double)'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'float16_val' '_Float16'
+
+int f_3(_Float16) {} // expected-note {{candidate function not viable: no known conversion from 'float' to '_Float16' for 1st argument}} expected-note {{no known conversion from 'decltype(0.BF16)' (aka '__bf16') to '_Float16' for 1st argument}}
+int test_13 = f_3(float_val); // expected-error {{no matching function for call to 'f_3'}}
+int test_14 = f_3(bf16_val); // expected-error {{no matching function for call to 'f_3'}}
+int test_15 = f_3(static_cast<_Float16>(bf16_val)); // expected-error {{static_cast from 'decltype(0.BF16)' (aka '__bf16') to '_Float16' is not allowed}}
+
+int f_4(decltype(0.0BF16)) {} // expected-note {{candidate function not viable: no known conversion from 'float' to 'decltype(0.BF16)' (aka '__bf16') for 1st argument}} expected-note {{candidate function not viable: no known conversion from '_Float16' to 'decltype(0.BF16)' (aka '__bf16') for 1st argument}}
+int test_16 = f_4(float_val); // expected-error {{no matching function for call to 'f_4'}}
+int test_17 = f_4(float16_val); // expected-error {{no matching function for call to 'f_4'}}
+int test_18 = f_4(static_cast<decltype(0.0BF16)>(float16_val)); // expected-error {{static_cast from '_Float16' to 'decltype(0.BF16)' (aka '__bf16') is not allowed}}
+
+struct S {
+ operator decltype(0.0BF16)() const {
+ return 0.0bf16;
+ }
+ operator _Float16() const {
+ return 0.0f16;
+ }
+ operator float() const {
+ return 0.0f;
+ }
+ operator double() const {
+ return 0.0;
+ }
+ operator long double() const {
+ return 0.0L;
+ }
+ operator int() const {
+ return 0;
+ }
+};
+
+
+S user_defined_val;
+// User-defined overload cases
+decltype(0.0BF16) bfloat16_val(user_defined_val); // calls operator decltype(0.BF16)()
+//CHECK: VarDecl {{.*}} bfloat16_val 'decltype(0.BF16)':'__bf16' callinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' <UserDefinedConversion>
+//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'decltype(0.BF16)':'__bf16'
+//CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator __bf16 {{.*}}
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue <NoOp>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'S' lvalue Var {{.*}} 'user_defined_val' 'S'
+_Float16 f16_val(user_defined_val); // calls operator _Float16()
+//CHECK: VarDecl {{.*}} f16_val '_Float16' callinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <UserDefinedConversion>
+//CHECK-NEXT: CXXMemberCallExpr {{.*}} '_Float16
+//CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator _Float16 {{.*}}
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue <NoOp>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'S' lvalue Var {{.*}} 'user_defined_val' 'S'
+float f_val(user_defined_val); // calls operator float()
+//CHECK: VarDecl {{.*}} f_val 'float' callinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <UserDefinedConversion>
+//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'float'
+//CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator float {{.*}}
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue <NoOp>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'S' lvalue Var {{.*}} 'user_defined_val' 'S'
+double d_val(user_defined_val); // calls operator double()
+//CHECK: VarDecl {{.*}} d_val 'double' callinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <UserDefinedConversion>
+//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'double'
+//CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator double {{.*}}
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue <NoOp>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'S' lvalue Var {{.*}} 'user_defined_val' 'S'
+long double ld_val(user_defined_val); // calls operator long double()
+//CHECK: VarDecl {{.*}} ld_val 'long double' callinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <UserDefinedConversion>
+//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'long double'
+//CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator long double {{.*}}
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue <NoOp>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'S' lvalue Var {{.*}} 'user_defined_val' 'S'
+int i_val(user_defined_val); // calls operator int()
+//CHECK: VarDecl {{.*}} i_val 'int' callinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <UserDefinedConversion>
+//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'int'
+//CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator int {{.*}}
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue <NoOp>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'S' lvalue Var {{.*}} 'user_defined_val' 'S'
+struct S1 {
+ operator _Float16() const {
+ return 0.0f16;
+ }
+ operator float() const {
+ return 0.0f;
+ }
+ operator double() const {
+ return 0.0;
+ }
+ operator long double() const {
+ return 0.0L;
+ }
+ operator int() const {
+ return 0;
+ }
+};
+
+S1 user_defined_val_2;
+// User-defined overload cases
+decltype(0.0BF16) bfloat16_val_2(user_defined_val_2); // calls operator int()
+//CHECK: VarDecl {{.*}} bfloat16_val_2 'decltype(0.BF16)':'__bf16' callinit
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' <IntegralToFloating>
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <UserDefinedConversion>
+//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'int'
+//CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator int {{.*}}
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S1' lvalue <NoOp>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'S1' lvalue Var {{.*}} 'user_defined_val_2' 'S1'
+struct S2 {
+ operator decltype(0.0BF16)() const { // expected-note {{candidate function}}
+ return 0.0bf16;
+ }
+
+ operator _Float16() const { // expected-note {{candidate function}}
+ return 0.0f16;
+ }
+ operator double() const { // expected-note {{candidate function}}
+ return 0.0;
+ }
+ operator long double() const { // expected-note {{candidate function}}
+ return 0.0L;
+ }
+ operator int() const { // expected-note {{candidate function}}
+ return 0;
+ }
+};
+
+S2 user_defined_val_3;
+// User-defined overload cases
+float float_val_2(user_defined_val_3); // expected-error {{conversion from 'S2' to 'float' is ambiguous}}
+
+// Test case for varadic function
+int f_5(int a, ...) {
+ va_list ap;
+ va_start(ap, a);
+ auto bf16_val = va_arg(ap, decltype(0.BF16));
+ auto float16_val = va_arg(ap, _Float16);
+ auto promoted_float_val = va_arg(ap, double);
+ auto double_val = va_arg(ap, double);
+ auto long_double_val = va_arg(ap, long double);
+ auto int_val = va_arg(ap, int);
+ va_end(ap);
+}
+// CHECK: VarDecl {{.*}} used ap 'va_list'
+// CHECK: VarDecl {{.*}} bf16_val 'decltype(0.BF16)'
+// CHECK: VarDecl {{.*}} float16_val '_Float16'
+// CHECK: VarDecl {{.*}} promoted_float_val 'double'
+// CHECK: VarDecl {{.*}} double_val 'double'
+// CHECK: VarDecl {{.*}} long_double_val 'long double'
+// CHECK: VarDecl {{.*}} int_val 'int'
+
+int test_19 = f_5(0, bf16_val, float16_val, float_val, double_val, long_double_val, int_val);
+//CHECK: VarDecl {{.*}} test_19 'int' cinit
+//CHECK-NEXT: CallExpr {{.*}} 'int'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(int, ...)' <FunctionToPointerDecay>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int (int, ...)' lvalue Function {{.*}} 'f_5' 'int (int, ...)'
+//CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'decltype(0.BF16)':'__bf16' lvalue Var {{.*}} 'bf16_val' 'decltype(0.BF16)':'__bf16'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'float16_val' '_Float16'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue Var {{.*}} 'float_val' 'float'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'double' lvalue Var {{.*}} 'double_val' 'double'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'long double' lvalue Var {{.*}} 'long_double_val' 'long double'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+//CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'int_val' 'int'
More information about the cfe-commits
mailing list