Index: clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp +++ clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp @@ -402,7 +402,8 @@ if ((Cast->getCastKind() == CK_NoOp && Context->hasSameType(Cast->getType(), E->getType().withConst())) || (Cast->getCastKind() == CK_LValueToRValue && - !Cast->getType().isNull() && Cast->getType()->isFundamentalType())) + !Cast->getType().isNull() && + Cast->getType()->isFundamentalType(*Context))) return false; } // FIXME: Make this function more generic. @@ -624,7 +625,8 @@ SourceRange ParenRange(Loop->getLParenLoc(), Loop->getRParenLoc()); QualType Type = Context->getAutoDeductType(); - if (!Descriptor.ElemType.isNull() && Descriptor.ElemType->isFundamentalType()) + if (!Descriptor.ElemType.isNull() && + Descriptor.ElemType->isFundamentalType(*Context)) Type = Descriptor.ElemType.getUnqualifiedType(); Type = Type.getDesugaredType(*Context); Index: clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp +++ clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp @@ -410,7 +410,7 @@ return true; // Arithmetic types are interconvertible, except scoped enums. - if (ParamType->isArithmeticType() && ArgType->isArithmeticType()) { + if (ParamType->isArithmeticType(Ctx) && ArgType->isArithmeticType(Ctx)) { if ((ParamType->isEnumeralType() && ParamType->castAs()->getDecl()->isScoped()) || (ArgType->isEnumeralType() && Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -799,7 +799,9 @@ ``_Float16`` will be supported on more targets as they define ABIs for it. -``__bf16`` is purely a storage format; it is currently only supported on the following targets: +``__bf16`` is an arithmetic type on targets with native bfloat16 arithmetic support, +and a storage-only type on targets that lack such support but can store bfloat16, +such as: * 32-bit ARM * 64-bit ARM (AArch64) Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -58,6 +58,16 @@ 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; @@ -1099,7 +1109,7 @@ CanQualType SatUnsignedShortFractTy, SatUnsignedFractTy, SatUnsignedLongFractTy; CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON - CanQualType BFloat16Ty; + CanQualType BFloat16Ty; // [C++23 6.8.3p5], ISO/IEC/IEEE 60559. CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3 CanQualType VoidPtrTy, NullPtrTy; CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; @@ -2789,14 +2799,21 @@ /// 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; unsigned getTargetAddressSpace(LangAS AS) const; Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -2149,17 +2149,29 @@ 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) + bool isCXX23FloatingPointType(const ASTContext &Ctx) + const; // C++23 6.8.2p12 [basic.fundamental] (standard floating point + + // extended floating point) + bool isCXX23StandardFloatingPointType(const ASTContext &Ctx) + const; // C++23 6.8.2p12 [basic.fundamental] (standard floating point) + bool isCXX23ExtendedFloatingPointType(const ASTContext &Ctx) + const; // C++23 6.8.2p12 [basic.fundamental] (extended floating point) + bool isCXX23StandardAndExtendedFpOp(const ASTContext &Ctx, QualType &Type) + const; // C++23 6.8.2p12 [basic.fundamental] (Used to determine if at + // least one of the types is a standard floating-point type and the + // other is an extended floating-point type) 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; bool isFloat128Type() const; bool isIbm128Type() const; bool isRealType() const; // C99 6.2.5p17 (real floating + integer) - bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) + bool isArithmeticType( + const ASTContext &Ctx) const;// C99 6.2.5p18 (integer + floating) bool isVoidType() const; // C99 6.2.5p19 bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers) bool isAggregateType() const; - bool isFundamentalType() const; + bool isFundamentalType(const ASTContext &Ctx) const; bool isCompoundType() const; // Type Predicates: Check to see if this type is structurally the specified @@ -6886,12 +6898,11 @@ /// Tests whether the type is categorized as a fundamental type. /// /// \returns True for types specified in C++0x [basic.fundamental]. -inline bool Type::isFundamentalType() const { - return isVoidType() || - isNullPtrType() || +inline bool Type::isFundamentalType(const ASTContext &Ctx) const { + return isVoidType() || isNullPtrType() || // FIXME: It's really annoying that we don't have an // 'isArithmeticType()' which agrees with the standard definition. - (isArithmeticType() && !isEnumeralType()); + (isArithmeticType(Ctx) && !isEnumeralType()); } /// Tests whether the type is categorized as a compound type. Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8750,6 +8750,7 @@ >; def err_cast_to_bfloat16 : Error<"cannot type-cast to __bf16">; def err_cast_from_bfloat16 : Error<"cannot type-cast from __bf16">; +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< Index: clang/include/clang/Basic/TargetInfo.h =================================================================== --- clang/include/clang/Basic/TargetInfo.h +++ clang/include/clang/Basic/TargetInfo.h @@ -219,6 +219,7 @@ bool HasFloat128; bool HasFloat16; bool HasBFloat16; + bool HasFullBFloat16; bool HasIbm128; bool HasLongDouble; bool HasFPReturn; @@ -650,6 +651,10 @@ /// Determine whether the _BFloat16 type is supported on this target. virtual bool hasBFloat16Type() const { return HasBFloat16; } + /// Determine whether the BFloat type is fully supported on this target, i.e + /// arithemtic operations. + virtual bool hasFullBFloat16Type() const { return HasFullBFloat16; } + /// Determine whether the __ibm128 type is supported on this target. virtual bool hasIbm128Type() const { return HasIbm128; } Index: clang/include/clang/Lex/LiteralSupport.h =================================================================== --- clang/include/clang/Lex/LiteralSupport.h +++ clang/include/clang/Lex/LiteralSupport.h @@ -72,6 +72,7 @@ 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 (C2x) + bool isBFloat16 : 1; // 1.0bf uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64. Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h +++ 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" @@ -601,7 +602,7 @@ // Perform type conversion if ((LTy->isIntegralOrEnumerationType() && RTy->isIntegralOrEnumerationType()) && - (LTy->isArithmeticType() && RTy->isArithmeticType())) { + (LTy->isArithmeticType(Ctx) && RTy->isArithmeticType(Ctx))) { SMTConv::doIntTypeConversion( Solver, Ctx, LHS, LTy, RHS, RTy); return; @@ -775,11 +776,11 @@ // 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 { Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -112,6 +112,83 @@ 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: + 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, 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 location that is relevant when searching for Doc comments related /// to \p D. static SourceLocation getDeclLocForCommentSearch(const Decl *D, @@ -2136,7 +2213,7 @@ Align = Target->getLongFractAlign(); break; case BuiltinType::BFloat16: - if (Target->hasBFloat16Type()) { + if (Target->hasBFloat16Type() || Target->hasFullBFloat16Type()) { Width = Target->getBFloat16Width(); Align = Target->getBFloat16Align(); } else if ((getLangOpts().SYCLIsDevice || @@ -7077,24 +7154,47 @@ } } +/// 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()) + LHSKind = CT->getElementType()->castAs()->getKind(); + else + LHSKind = LHS->castAs()->getKind(); + if (const auto *CT = RHS->getAs()) + RHSKind = CT->getElementType()->castAs()->getKind(); + else + RHSKind = RHS->castAs()->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); } Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1109,7 +1109,7 @@ if (!DiscardResult && AK == DerefKind::Read) { if (VD->hasLocalStorage() && VD->hasInit() && !VD->isConstexpr()) { QualType VT = VD->getType(); - if (VT.isConstQualified() && VT->isFundamentalType()) + if (VT.isConstQualified() && VT->isFundamentalType(VD->getASTContext())) return this->visit(VD->getInit()); } } Index: clang/lib/AST/StmtPrinter.cpp =================================================================== --- clang/lib/AST/StmtPrinter.cpp +++ clang/lib/AST/StmtPrinter.cpp @@ -1348,6 +1348,7 @@ case BuiltinType::Float: OS << 'F'; break; case BuiltinType::LongDouble: OS << 'L'; break; case BuiltinType::Float128: OS << 'Q'; break; + case BuiltinType::BFloat16: OS << "BF16"; break; } } Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -2157,6 +2157,42 @@ return false; } +bool Type::isCXX23StandardFloatingPointType(const ASTContext &Ctx) const { + if (!Ctx.getLangOpts().CPlusPlus23) + return false; + if (const auto *BT = dyn_cast(CanonicalType)) + return BT->getKind() >= BuiltinType::Float && + BT->getKind() <= BuiltinType::LongDouble; + if (const auto *CT = dyn_cast(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(CanonicalType)) + return BT->getKind() == BuiltinType::Float16 || + (Ctx.getTargetInfo().hasFullBFloat16Type() && + (BT->getKind() == BuiltinType::BFloat16)); + if (const auto *CT = dyn_cast(CanonicalType)) + return CT->getElementType()->isCXX23ExtendedFloatingPointType(Ctx); + return false; +} + +bool Type::isCXX23FloatingPointType(const ASTContext &Ctx) const { + return isCXX23StandardFloatingPointType(Ctx) || + isCXX23ExtendedFloatingPointType(Ctx); +} + +bool Type::isCXX23StandardAndExtendedFpOp(const ASTContext &Ctx, + QualType &Type) const { + return (((isCXX23FloatingPointType(Ctx) && + Type->isCXX23FloatingPointType(Ctx))) && + (isCXX23ExtendedFloatingPointType(Ctx) || + Type->isCXX23ExtendedFloatingPointType(Ctx))); +} + bool Type::hasFloatingRepresentation() const { if (const auto *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isFloatingType(); @@ -2180,11 +2216,12 @@ return isBitIntType(); } -bool Type::isArithmeticType() const { +bool Type::isArithmeticType(const ASTContext &Ctx) const { if (const auto *BT = dyn_cast(CanonicalType)) - return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::Ibm128 && - BT->getKind() != BuiltinType::BFloat16; + return (BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Ibm128 && + (BT->getKind() != BuiltinType::BFloat16 || + Ctx.getTargetInfo().hasFullBFloat16Type())); if (const auto *ET = dyn_cast(CanonicalType)) // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). // If a body isn't seen by the time we get here, return false. Index: clang/lib/Basic/TargetInfo.cpp =================================================================== --- clang/lib/Basic/TargetInfo.cpp +++ clang/lib/Basic/TargetInfo.cpp @@ -64,6 +64,7 @@ HasIbm128 = false; HasFloat16 = false; HasBFloat16 = false; + HasFullBFloat16 = false; HasLongDouble = true; HasFPReturn = true; HasStrictFP = false; Index: clang/lib/Basic/Targets/AMDGPU.h =================================================================== --- clang/lib/Basic/Targets/AMDGPU.h +++ clang/lib/Basic/Targets/AMDGPU.h @@ -118,8 +118,8 @@ } bool hasBFloat16Type() const override { return isAMDGCN(getTriple()); } - const char *getBFloat16Mangling() const override { return "u6__bf16"; }; - + const char *getBFloat16Mangling() const override { return "DF16b"; }; + std::string_view getClobbers() const override { return ""; } ArrayRef getGCCRegNames() const override; Index: clang/lib/Basic/Targets/ARM.cpp =================================================================== --- clang/lib/Basic/Targets/ARM.cpp +++ clang/lib/Basic/Targets/ARM.cpp @@ -514,6 +514,7 @@ HasFloat16 = true; ARMCDECoprocMask = 0; HasBFloat16 = false; + HasFullBFloat16 = false; FPRegsDisabled = false; // This does not diagnose illegal cases like having both Index: clang/lib/Basic/Targets/NVPTX.h =================================================================== --- clang/lib/Basic/Targets/NVPTX.h +++ clang/lib/Basic/Targets/NVPTX.h @@ -181,7 +181,7 @@ bool hasBitIntType() const override { return true; } bool hasBFloat16Type() const override { return true; } - const char *getBFloat16Mangling() const override { return "u6__bf16"; }; + const char *getBFloat16Mangling() const override { return "DF16b"; }; }; } // namespace targets } // namespace clang Index: clang/lib/Basic/Targets/X86.h =================================================================== --- clang/lib/Basic/Targets/X86.h +++ clang/lib/Basic/Targets/X86.h @@ -417,7 +417,7 @@ return getPointerWidthV(AddrSpace); } - const char *getBFloat16Mangling() const override { return "u6__bf16"; }; + const char *getBFloat16Mangling() const override { return "DF16b"; }; }; // X86-32 generic target Index: clang/lib/Basic/Targets/X86.cpp =================================================================== --- clang/lib/Basic/Targets/X86.cpp +++ clang/lib/Basic/Targets/X86.cpp @@ -359,6 +359,8 @@ HasCRC32 = true; } else if (Feature == "+x87") { HasX87 = true; + } else if (Feature == "+fullbf16") { + HasFullBFloat16 = true; } X86SSEEnum Level = llvm::StringSwitch(Feature) @@ -1117,6 +1119,7 @@ .Case("xsavec", HasXSAVEC) .Case("xsaves", HasXSAVES) .Case("xsaveopt", HasXSAVEOPT) + .Case("fullbf16", HasFullBFloat16) .Default(false); } Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -3000,7 +3000,7 @@ // __imag can only produce an rvalue on scalars. if (E->getOpcode() == UO_Real && !LV.getAddress(*this).getElementType()->isStructTy()) { - assert(E->getSubExpr()->getType()->isArithmeticType()); + assert(E->getSubExpr()->getType()->isArithmeticType(getContext())); return LV; } Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ clang/lib/CodeGen/CGExprScalar.cpp @@ -3446,7 +3446,8 @@ assert( isa(BO->getLHS()->getType().getCanonicalType()) && "first operand must be a matrix"); - assert(BO->getRHS()->getType().getCanonicalType()->isArithmeticType() && + assert(BO->getRHS()->getType().getCanonicalType()->isArithmeticType( + CGF.getContext()) && "second operand must be an arithmetic type"); CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Ops.FPFeatures); return MB.CreateScalarDiv(Ops.LHS, Ops.RHS, Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -5566,7 +5566,7 @@ QualType Ty) const override; bool allowBFloatArgsAndRet() const override { - return getTarget().hasBFloat16Type(); + return getTarget().hasBFloat16Type() || getTarget().hasFullBFloat16Type(); } }; @@ -6363,7 +6363,8 @@ ABIKind getABIKind() const { return Kind; } bool allowBFloatArgsAndRet() const override { - return !IsFloatABISoftFP && getTarget().hasBFloat16Type(); + return !IsFloatABISoftFP && + (getTarget().hasBFloat16Type() || getTarget().hasFullBFloat16Type()); } private: Index: clang/lib/Frontend/InitPreprocessor.cpp =================================================================== --- clang/lib/Frontend/InitPreprocessor.cpp +++ clang/lib/Frontend/InitPreprocessor.cpp @@ -452,8 +452,13 @@ } else { // -- __cplusplus // FIXME: Use correct value for C++23. - if (LangOpts.CPlusPlus23) + if (LangOpts.CPlusPlus23) { Builder.defineMacro("__cplusplus", "202101L"); + // [C++23] 15.11p2 [cpp.predefined] + Builder.defineMacro("__STDCPP_FLOAT16_T__", "1"); + if (TI.hasFullBFloat16Type()) + Builder.defineMacro("__STDCPP_BFLOAT16_T__", "1"); + } // [C++20] The integer literal 202002L. else if (LangOpts.CPlusPlus20) Builder.defineMacro("__cplusplus", "202002L"); Index: clang/lib/Lex/LiteralSupport.cpp =================================================================== --- clang/lib/Lex/LiteralSupport.cpp +++ clang/lib/Lex/LiteralSupport.cpp @@ -858,6 +858,7 @@ 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 @@ -958,6 +959,23 @@ 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 (!LangOpts.CPlusPlus23 || !Target.hasFullBFloat16Type()) + break; + 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. @@ -1090,6 +1108,7 @@ saw_fixed_point_suffix = false; isFract = false; isAccum = false; + isBFloat16 = false; } saw_ud_suffix = true; Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -694,6 +694,23 @@ } } + // 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 (ExprTy->isCXX23StandardAndExtendedFpOp(Context, TypeTy) && + Kind == CK_FloatingCast && E->isPRValue() && + (CCK == CCK_ImplicitConversion)) { + auto conversionRank = Context.getFloatingTypeOrder(TypeTy, ExprTy); + if (conversionRank < FRCR_Greater) { + Diag(E->getExprLoc(), + diag::err_cxx23_invalid_implicit_floating_point_cast) + << E->getSourceRange(); + return ExprError(); + } + } + if (ImplicitCastExpr *ImpCast = dyn_cast(E)) { if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) { ImpCast->setType(Ty); @@ -1975,7 +1992,9 @@ (Ty->isIbm128Type() && !Context.getTargetInfo().hasIbm128Type()) || (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 && !Context.getTargetInfo().hasInt128Type()) || - (Ty->isBFloat16Type() && !Context.getTargetInfo().hasBFloat16Type() && + (Ty->isBFloat16Type() && + !(Context.getTargetInfo().hasBFloat16Type() || + Context.getTargetInfo().hasFullBFloat16Type()) && !LangOpts.CUDAIsDevice) || LongDoubleMismatched) { PartialDiagnostic PD = PDiag(diag::err_target_unsupported_type); Index: clang/lib/Sema/SemaCast.cpp =================================================================== --- clang/lib/Sema/SemaCast.cpp +++ clang/lib/Sema/SemaCast.cpp @@ -1359,6 +1359,19 @@ } } + // [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() && + DestType->isCXX23StandardAndExtendedFpOp(Self.Context, SrcType)) { + // 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). @@ -3108,8 +3121,9 @@ // If either type is a pointer, the other type has to be either an // integer or a pointer. - if (!DestType->isArithmeticType()) { - if (!SrcType->isIntegralType(Self.Context) && SrcType->isArithmeticType()) { + if (!DestType->isArithmeticType(Self.Context)) { + if (!SrcType->isIntegralType(Self.Context) && + SrcType->isArithmeticType(Self.Context)) { Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_pointer_from_non_pointer_int) << SrcType << SrcExpr.get()->getSourceRange(); @@ -3118,9 +3132,9 @@ } checkIntToPointerCast(/* CStyle */ true, OpRange, SrcExpr.get(), DestType, Self); - } else if (!SrcType->isArithmeticType()) { + } else if (!SrcType->isArithmeticType(Self.Context)) { if (!DestType->isIntegralType(Self.Context) && - DestType->isArithmeticType()) { + DestType->isArithmeticType(Self.Context)) { Self.Diag(SrcExpr.get()->getBeginLoc(), diag::err_cast_pointer_to_non_pointer_int) << DestType << SrcExpr.get()->getSourceRange(); Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -10403,7 +10403,7 @@ 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 @@ -13693,9 +13693,12 @@ 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); @@ -14121,7 +14124,7 @@ 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; @@ -14139,7 +14142,7 @@ 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; Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -793,7 +793,7 @@ 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, @@ -802,7 +802,8 @@ : 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( @@ -1153,14 +1154,16 @@ 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 @@ -1213,16 +1216,34 @@ 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; @@ -1559,7 +1580,8 @@ // If either side is a non-arithmetic type (e.g. a pointer), we are done. // The caller can deal with this (e.g. pointer + int). - if (!LHSType->isArithmeticType() || !RHSType->isArithmeticType()) + if (!LHSType->isArithmeticType(Context) || + !RHSType->isArithmeticType(Context)) return QualType(); // Apply unary and bitfield promotions to the LHS's type. @@ -3933,6 +3955,8 @@ Ty = Context.Float16Ty; else if (Literal.isFloat128) Ty = Context.Float128Ty; + else if (Literal.isBFloat16) + Ty = Context.BFloat16Ty; else Ty = Context.DoubleTy; @@ -4180,7 +4204,8 @@ // scalar or vector data type argument..." // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic // type (C99 6.2.5p18) or void. - if (!(T->isArithmeticType() || T->isVoidType() || T->isVectorType())) { + if (!(T->isArithmeticType(S.Context) || T->isVoidType() || + T->isVectorType())) { S.Diag(Loc, diag::err_vecstep_non_scalar_vector_type) << T << ArgRange; return true; @@ -4725,7 +4750,7 @@ return CT->getElementType(); // Otherwise they pass through real integer and floating point types here. - if (V.get()->getType()->isArithmeticType()) + if (V.get()->getType()->isArithmeticType(S.Context)) return V.get()->getType(); // Test for placeholders. @@ -8972,7 +8997,7 @@ // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. - if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) { + if (LHSTy->isArithmeticType(Context) && RHSTy->isArithmeticType(Context)) { // Disallow invalid arithmetic conversions, such as those between bit- // precise integers types of different sizes, or between a bit-precise // integer and another type. @@ -9873,7 +9898,7 @@ if (LHSType->isExtVectorType()) { if (RHSType->isExtVectorType()) return Incompatible; - if (RHSType->isArithmeticType()) { + if (RHSType->isArithmeticType(Context)) { // CK_VectorSplat does T -> vector T, so first cast to the element type. if (ConvertRHS) RHS = prepareVectorSplat(LHSType, RHS.get()); @@ -9964,7 +9989,8 @@ return Incompatible; // Arithmetic conversions. - if (LHSType->isArithmeticType() && RHSType->isArithmeticType() && + if (LHSType->isArithmeticType(Context) && + RHSType->isArithmeticType(Context) && !(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) { if (ConvertRHS) Kind = PrepareScalarCast(RHS, LHSType); @@ -10539,7 +10565,8 @@ } 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; } @@ -10686,7 +10713,8 @@ // Reject cases where the vector element type or the scalar element type are // not integral or floating point types. - if (!VectorEltTy->isArithmeticType() || !ScalarTy->isArithmeticType()) + if (!VectorEltTy->isArithmeticType(S.Context) || + !ScalarTy->isArithmeticType(S.Context)) return true; // The conversion to apply to the scalar before splatting it, @@ -10727,8 +10755,19 @@ // 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.getLangOpts().CPlusPlus23 && + (ScalarTy->isCXX23StandardAndExtendedFpOp(S.Context, VectorEltTy)) && + (Order <= FRCR_Lesser)) + return true; + + if (!CstScalar && (Order == FRCR_Lesser)) return true; // If the scalar cannot be safely casted to the vector element type, @@ -10785,8 +10824,9 @@ const VectorType *RHSVecType = RHSType->getAs(); assert(LHSVecType || RHSVecType); - if ((LHSVecType && LHSVecType->getElementType()->isBFloat16Type()) || - (RHSVecType && RHSVecType->getElementType()->isBFloat16Type())) + if (!Context.getTargetInfo().hasFullBFloat16Type() && + ((LHSVecType && LHSVecType->getElementType()->isBFloat16Type()) || + (RHSVecType && RHSVecType->getElementType()->isBFloat16Type()))) return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType(); // AltiVec-style "vector bool op vector bool" combinations are allowed @@ -11211,7 +11251,8 @@ return CheckMatrixMultiplyOperands(LHS, RHS, Loc, IsCompAssign); // For division, only matrix-by-scalar is supported. Other combinations with // matrix types are invalid. - if (IsDiv && LHSTy->isConstantMatrixType() && RHSTy->isArithmeticType()) + if (IsDiv && LHSTy->isConstantMatrixType() && + RHSTy->isArithmeticType(Context)) return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign); QualType compType = UsualArithmeticConversions( @@ -11219,8 +11260,7 @@ if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); - - if (compType.isNull() || !compType->isArithmeticType()) + if (compType.isNull() || !compType->isArithmeticType(Context)) return InvalidOperands(Loc, LHS, RHS); if (IsDiv) { DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv); @@ -11594,7 +11634,7 @@ } // handle the common case first (both operands are arithmetic). - if (!compType.isNull() && compType->isArithmeticType()) { + if (!compType.isNull() && compType->isArithmeticType(Context)) { if (CompLHSTy) *CompLHSTy = compType; return compType; } @@ -11705,7 +11745,7 @@ // Enforce type constraints: C99 6.5.6p3. // Handle the common case first (both operands are arithmetic). - if (!compType.isNull() && compType->isArithmeticType()) { + if (!compType.isNull() && compType->isArithmeticType(Context)) { if (CompLHSTy) *CompLHSTy = compType; return compType; } @@ -12666,7 +12706,7 @@ } QualType IntType = LHSStrippedType->castAs()->getDecl()->getIntegerType(); - assert(IntType->isArithmeticType()); + assert(IntType->isArithmeticType(S.Context)); // We can't use `CK_IntegralCast` when the underlying type is 'bool', so we // promote the boolean type, and all other promotable integer types, to @@ -12720,7 +12760,7 @@ return QualType(); if (Type.isNull()) return S.InvalidOperands(Loc, LHS, RHS); - assert(Type->isArithmeticType() || Type->isEnumeralType()); + assert(Type->isArithmeticType(S.Context) || Type->isEnumeralType()); if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc)) return S.InvalidOperands(Loc, LHS, RHS); @@ -12812,8 +12852,8 @@ QualType LHSType = LHS.get()->getType(); QualType RHSType = RHS.get()->getType(); - if ((LHSType->isArithmeticType() || LHSType->isEnumeralType()) && - (RHSType->isArithmeticType() || RHSType->isEnumeralType())) + if ((LHSType->isArithmeticType(Context) || LHSType->isEnumeralType()) && + (RHSType->isArithmeticType(Context) || RHSType->isEnumeralType())) return checkArithmeticOrEnumeralCompare(*this, LHS, RHS, Loc, Opc); const Expr::NullPointerConstantKind LHSNullKind = @@ -16014,7 +16054,7 @@ resultType = Input.get()->getType(); if (resultType->isDependentType()) break; - if (resultType->isArithmeticType()) // C99 6.5.3.3p1 + if (resultType->isArithmeticType(Context)) // C99 6.5.3.3p1 break; else if (resultType->isVectorType() && // The z vector extensions don't allow + or - with bool vectors. Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -5004,9 +5004,9 @@ case UTT_IsReference: return T->isReferenceType(); case UTT_IsArithmetic: - return T->isArithmeticType() && !T->isEnumeralType(); + return T->isArithmeticType(C) && !T->isEnumeralType(); case UTT_IsFundamental: - return T->isFundamentalType(); + return T->isFundamentalType(C); case UTT_IsObject: return T->isObjectType(); case UTT_IsScalar: @@ -6712,7 +6712,7 @@ // -- The second and third operands have arithmetic or enumeration type; // the usual arithmetic conversions are performed to bring them to a // common type, and the result is of that type. - if (LTy->isArithmeticType() && RTy->isArithmeticType()) { + if (LTy->isArithmeticType(Context) && RTy->isArithmeticType(Context)) { QualType ResTy = UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); if (LHS.isInvalid() || RHS.isInvalid()) Index: clang/lib/Sema/SemaObjCProperty.cpp =================================================================== --- clang/lib/Sema/SemaObjCProperty.cpp +++ clang/lib/Sema/SemaObjCProperty.cpp @@ -1386,8 +1386,7 @@ // specifically for property redeclarations as well as for ivars. QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType(); QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType(); - if (lhsType != rhsType && - lhsType->isArithmeticType()) { + if (lhsType != rhsType && lhsType->isArithmeticType(Context)) { Diag(PropertyDiagLoc, diag::err_property_ivar_type) << property->getDeclName() << PropType << Ivar->getDeclName() << IvarType; @@ -1733,7 +1732,7 @@ compat = true; QualType lhsType = Context.getCanonicalType(PropertyRValueType); QualType rhsType =Context.getCanonicalType(GetterType).getUnqualifiedType(); - if (lhsType != rhsType && lhsType->isArithmeticType()) + if (lhsType != rhsType && lhsType->isArithmeticType(Context)) compat = false; } } Index: clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- clang/lib/Sema/SemaOpenMP.cpp +++ clang/lib/Sema/SemaOpenMP.cpp @@ -19366,7 +19366,7 @@ if (DeclareReductionRef.isUnset()) { if ((BOK == BO_GT || BOK == BO_LT) && !(Type->isScalarType() || - (S.getLangOpts().CPlusPlus && Type->isArithmeticType()))) { + (S.getLangOpts().CPlusPlus && Type->isArithmeticType(Context)))) { S.Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) << getOpenMPClauseName(ClauseKind) << S.getLangOpts().CPlusPlus; if (!ASE && !OASE) { Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -397,7 +397,7 @@ // 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); @@ -1750,7 +1750,7 @@ return false; // Vector splat from any arithmetic type to a vector. - if (FromType->isArithmeticType()) { + if (FromType->isArithmeticType(S.Context)) { ICK = ICK_Vector_Splat; return true; } @@ -1969,9 +1969,8 @@ SCS.Second = ICK_Complex_Promotion; FromType = ToType.getUnqualifiedType(); } else if (ToType->isBooleanType() && - (FromType->isArithmeticType() || - FromType->isAnyPointerType() || - FromType->isBlockPointerType() || + (FromType->isArithmeticType(S.Context) || + FromType->isAnyPointerType() || FromType->isBlockPointerType() || FromType->isMemberPointerType())) { // Boolean conversions (C++ 4.12). SCS.Second = ICK_Boolean_Conversion; @@ -1985,8 +1984,10 @@ // Complex conversions (C99 6.3.1.6) SCS.Second = ICK_Complex_Conversion; FromType = ToType.getUnqualifiedType(); - } else if ((FromType->isAnyComplexType() && ToType->isArithmeticType()) || - (ToType->isAnyComplexType() && FromType->isArithmeticType())) { + } else if ((FromType->isAnyComplexType() && + ToType->isArithmeticType(S.Context)) || + (ToType->isAnyComplexType() && + FromType->isArithmeticType(S.Context))) { // Complex-real conversions (C99 6.3.1.7) SCS.Second = ICK_Complex_Real; FromType = ToType.getUnqualifiedType(); @@ -1995,8 +1996,18 @@ // if their representation is different until there is back end support // We of course allow this conversion if long double is really double. + // 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 ((FromType->isCXX23StandardAndExtendedFpOp(S.Context, ToType)) && + (S.Context.getFloatingTypeOrder(ToType, FromType) <= FRCR_Lesser)) + return false; + // Conversions between bfloat and other floats are not permitted. - if (FromType == S.Context.BFloat16Ty || ToType == S.Context.BFloat16Ty) + if (!S.Context.getTargetInfo().hasFullBFloat16Type() && + (FromType->isBFloat16Type() || ToType->isBFloat16Type())) return false; // Conversions between IEEE-quad and IBM-extended semantics are not @@ -2018,7 +2029,8 @@ (FromType->isIntegralOrUnscopedEnumerationType() && ToType->isRealFloatingType())) { // Conversions between bfloat and int are not permitted. - if (FromType->isBFloat16Type() || ToType->isBFloat16Type()) + if (!S.Context.getTargetInfo().hasFullBFloat16Type() && + (FromType->isBFloat16Type() || ToType->isBFloat16Type())) return false; // Floating-integral conversions (C++ 4.9). @@ -4166,6 +4178,74 @@ ? 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 (S.Context.hasSameType(SCS1.getFromType(), SCS2.getFromType())) { + + if ((SCS1.Second == ICK_Floating_Conversion) && + (SCS1.getFromType()->isCXX23FloatingPointType(S.Context) && + SCS1.getToType(1)->isCXX23FloatingPointType(S.Context)) && + S.Context.getFloatingTypeOrder(SCS1.getToType(1), + SCS1.getFromType()) >= FRCR_Equal) { + + if ((SCS2.getToType(1)->isArithmeticType(S.Context)) && + SCS2.getFromType()->isCXX23FloatingPointType(S.Context)) { + + if (!SCS2.getToType(1)->isCXX23FloatingPointType(S.Context)) { + return ImplicitConversionSequence::Better; + } + + if (S.Context.getFloatingTypeOrder(SCS2.getToType(1), + SCS1.getFromType()) < FRCR_Equal) { + 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.getFromType()->isCXX23FloatingPointType(S.Context) && + SCS2.getToType(1)->isCXX23FloatingPointType(S.Context)) && + S.Context.getFloatingTypeOrder(SCS2.getToType(1), + SCS2.getFromType()) >= FRCR_Equal) { + if ((SCS1.getToType(1)->isArithmeticType(S.Context)) && + SCS1.getFromType()->isCXX23FloatingPointType(S.Context)) { + + if (!SCS1.getToType(1)->isCXX23FloatingPointType(S.Context)) { + return ImplicitConversionSequence::Worse; + } + + if (S.Context.getFloatingTypeOrder(SCS1.getToType(1), + SCS2.getFromType()) < FRCR_Equal) { + 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, @@ -8250,7 +8330,7 @@ // Flag if we encounter an arithmetic type. HasArithmeticOrEnumeralTypes = - HasArithmeticOrEnumeralTypes || Ty->isArithmeticType(); + HasArithmeticOrEnumeralTypes || Ty->isArithmeticType(Context); if (Ty->isObjCIdType() || Ty->isObjCClassType()) PointerTypes.insert(Ty); Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -1519,7 +1519,8 @@ break; case DeclSpec::TST_half: Result = Context.HalfTy; break; case DeclSpec::TST_BFloat16: - if (!S.Context.getTargetInfo().hasBFloat16Type() && + if (!(S.Context.getTargetInfo().hasBFloat16Type() || + S.Context.getTargetInfo().hasFullBFloat16Type()) && !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice) && !S.getLangOpts().SYCLIsDevice) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__bf16"; Index: clang/test/CodeGen/X86/bfloat-mangle.cpp =================================================================== --- clang/test/CodeGen/X86/bfloat-mangle.cpp +++ clang/test/CodeGen/X86/bfloat-mangle.cpp @@ -3,6 +3,6 @@ // RUN: %clang_cc1 -triple i386-windows-msvc -target-feature +sse2 -emit-llvm -o - %s | FileCheck %s --check-prefixes=WINDOWS // RUN: %clang_cc1 -triple x86_64-windows-msvc -target-feature +sse2 -emit-llvm -o - %s | FileCheck %s --check-prefixes=WINDOWS -// LINUX: define {{.*}}void @_Z3foou6__bf16(bfloat noundef %b) +// LINUX: define {{.*}}void @_Z3fooDF16b(bfloat noundef %b) // WINDOWS: define {{.*}}void @"?foo@@YAXU__bf16@__clang@@@Z"(bfloat noundef %b) void foo(__bf16 b) {} Index: clang/test/CodeGen/vector-bfloat16.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/vector-bfloat16.cpp @@ -0,0 +1,37 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +fullbf16 -S -emit-llvm %s -o - | FileCheck %s + +typedef __bf16 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; +} \ No newline at end of file Index: clang/test/CodeGenCUDA/amdgpu-bf16.cu =================================================================== --- clang/test/CodeGenCUDA/amdgpu-bf16.cu +++ clang/test/CodeGenCUDA/amdgpu-bf16.cu @@ -7,7 +7,7 @@ #include "Inputs/cuda.h" -// CHECK-LABEL: @_Z8test_argPu6__bf16u6__bf16( +// CHECK-LABEL: @_Z8test_argPDF16bDF16b( // CHECK-NEXT: entry: // CHECK-NEXT: [[OUT_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) // CHECK-NEXT: [[IN_ADDR:%.*]] = alloca bfloat, align 2, addrspace(5) @@ -29,7 +29,7 @@ *out = bf16; } -// CHECK-LABEL: @_Z9test_loadPu6__bf16S_( +// CHECK-LABEL: @_Z9test_loadPDF16bS_( // CHECK-NEXT: entry: // CHECK-NEXT: [[OUT_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) // CHECK-NEXT: [[IN_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) @@ -52,7 +52,7 @@ *out = bf16; } -// CHECK-LABEL: @_Z8test_retu6__bf16( +// CHECK-LABEL: @_Z8test_retDF16b( // CHECK-NEXT: entry: // CHECK-NEXT: [[RETVAL:%.*]] = alloca bfloat, align 2, addrspace(5) // CHECK-NEXT: [[IN_ADDR:%.*]] = alloca bfloat, align 2, addrspace(5) @@ -66,7 +66,7 @@ return in; } -// CHECK-LABEL: @_Z9test_callu6__bf16( +// CHECK-LABEL: @_Z9test_callDF16b( // CHECK-NEXT: entry: // CHECK-NEXT: [[RETVAL:%.*]] = alloca bfloat, align 2, addrspace(5) // CHECK-NEXT: [[IN_ADDR:%.*]] = alloca bfloat, align 2, addrspace(5) @@ -74,7 +74,7 @@ // CHECK-NEXT: [[IN_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[IN_ADDR]] to ptr // CHECK-NEXT: store bfloat [[IN:%.*]], ptr [[IN_ADDR_ASCAST]], align 2 // CHECK-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[IN_ADDR_ASCAST]], align 2 -// CHECK-NEXT: [[CALL:%.*]] = call contract noundef bfloat @_Z8test_retu6__bf16(bfloat noundef [[TMP0]]) #[[ATTR1:[0-9]+]] +// CHECK-NEXT: [[CALL:%.*]] = call contract noundef bfloat @_Z8test_retDF16b(bfloat noundef [[TMP0]]) #[[ATTR1:[0-9]+]] // CHECK-NEXT: ret bfloat [[CALL]] // __device__ __bf16 test_call( __bf16 in) { Index: clang/test/CodeGenCUDA/bf16.cu =================================================================== --- clang/test/CodeGenCUDA/bf16.cu +++ clang/test/CodeGenCUDA/bf16.cu @@ -6,12 +6,12 @@ #include "Inputs/cuda.h" -// CHECK-LABEL: .visible .func _Z8test_argPu6__bf16u6__bf16( -// CHECK: .param .b64 _Z8test_argPu6__bf16u6__bf16_param_0, -// CHECK: .param .b16 _Z8test_argPu6__bf16u6__bf16_param_1 +// CHECK-LABEL: .visible .func _Z8test_argPDF16bDF16b( +// CHECK: .param .b64 _Z8test_argPDF16bDF16b_param_0, +// CHECK: .param .b16 _Z8test_argPDF16bDF16b_param_1 // __device__ void test_arg(__bf16 *out, __bf16 in) { -// CHECK: ld.param.b16 %{{h.*}}, [_Z8test_argPu6__bf16u6__bf16_param_1]; +// CHECK: ld.param.b16 %{{h.*}}, [_Z8test_argPDF16bDF16b_param_1]; __bf16 bf16 = in; *out = bf16; // CHECK: st.b16 @@ -19,23 +19,23 @@ } -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) _Z8test_retu6__bf16( -// CHECK: .param .b16 _Z8test_retu6__bf16_param_0 +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) _Z8test_retDF16b( +// CHECK: .param .b16 _Z8test_retDF16b_param_0 __device__ __bf16 test_ret( __bf16 in) { -// CHECK: ld.param.b16 %h{{.*}}, [_Z8test_retu6__bf16_param_0]; +// CHECK: ld.param.b16 %h{{.*}}, [_Z8test_retDF16b_param_0]; return in; // CHECK: st.param.b16 [func_retval0+0], %h // CHECK: ret; } -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) _Z9test_callu6__bf16( -// CHECK: .param .b16 _Z9test_callu6__bf16_param_0 +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) _Z9test_callDF16b( +// CHECK: .param .b16 _Z9test_callDF16b_param_0 __device__ __bf16 test_call( __bf16 in) { -// CHECK: ld.param.b16 %h{{.*}}, [_Z9test_callu6__bf16_param_0]; +// CHECK: ld.param.b16 %h{{.*}}, [_Z9test_callDF16b_param_0]; // CHECK: st.param.b16 [param0+0], %h2; // CHECK: .param .b32 retval0; // CHECK: call.uni (retval0), -// CHECK-NEXT: _Z8test_retu6__bf16, +// CHECK-NEXT: _Z8test_retDF16b, // CHECK-NEXT: ( // CHECK-NEXT: param0 // CHECK-NEXT ); Index: clang/test/CodeGenCXX/cxx23-fp-ext-std-names-p1467r9.cpp =================================================================== --- /dev/null +++ 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(1.0f); + decltype(0.BF16) bf16_val_8 = static_cast(1.0); + decltype(0.BF16) bf16_val_9 = static_cast(1.0l); + decltype(0.BF16) bf16_val_10 = static_cast(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() +} Index: clang/test/CodeGenCXX/cxx23-vector-bfloat16.cpp =================================================================== --- /dev/null +++ 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> , 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); +} + Index: clang/test/Sema/cxx23-fp-ext-std-names-p1467r9.cpp =================================================================== --- /dev/null +++ clang/test/Sema/cxx23-fp-ext-std-names-p1467r9.cpp @@ -0,0 +1,465 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++23 -target-feature +fullbf16 -verify -ast-dump %s | FileCheck %s + +_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> +//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> +//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> +//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> +//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(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(1.0f); +//CHECK: VarDecl {{.*}} bf16_val_7 'decltype(0.BF16)':'__bf16' cinit +//CHECK-NEXT: CXXStaticCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' static_cast +//CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00 +decltype(0.0BF16) bf16_val_8 = static_cast(1.0); +//CHECK: VarDecl {{.*}} bf16_val_8 'decltype(0.BF16)':'__bf16' cinit +//CHECK-NEXT: CXXStaticCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' static_cast +//CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00 +decltype(0.0BF16) bf16_val_9 = static_cast(1.0l); +//CHECK: VarDecl {{.*}} bf16_val_9 'decltype(0.BF16)':'__bf16' cinit +//CHECK-NEXT: CXXStaticCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' static_cast +//CHECK-NEXT: FloatingLiteral {{.*}} 'long double' 1.000000e+00 +decltype(0.0BF16) bf16_val_10 = static_cast(1.0bf16); +//CHECK: VarDecl {{.*}} bf16_val_10 'decltype(0.BF16)':'__bf16' cinit +//CHECK-NEXT: CXXStaticCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' static_cast +//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00 + +float f_val_1 = 1.0f16; +//CHECK: VarDecl {{.*}} f_val_1 'float' cinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00 +float f_val_2 = 1.0bf16; +//CHECK: VarDecl {{.*}} f_val_2 'float' cinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00 +float f_val_3 = 1.0; +//CHECK: VarDecl {{.*}} f_val_3 'float' cinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +//CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00 +float f_val_4 = 1.0l; +//CHECK: VarDecl {{.*}} f_val_4 'float' cinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +//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' +//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00 +double d_val_2 = 1.0bf16; +//CHECK: VarDecl {{.*}} d_val_2 'double' cinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' +//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00 +double d_val_3 = 1.0f; +//CHECK: VarDecl {{.*}} d_val_3 'double' cinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' +//CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00 +double d_val_4 = 1.0l; +//CHECK: VarDecl {{.*}} d_val_4 'double' cinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' +//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' +//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' +//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' +//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' +//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':'float' cinit +//CHECK-NEXT: BinaryOperator {{.*}} 'float' '+' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +//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':'double' cinit +//CHECK-NEXT: BinaryOperator {{.*}} 'double' '+' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' +//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':'long double' cinit +//CHECK-NEXT: BinaryOperator {{.*}} 'long double' '+' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' +//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':'_Float16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +auto f16_uint = 1.0f16 + 1u; +//CHECK: VarDecl {{.*}} f16_uint '_Float16':'_Float16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1 +auto f16_long = 1.0f16 + 1l; +//CHECK: VarDecl {{.*}} f16_long '_Float16':'_Float16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'long' 1 +auto f16_ulong = 1.0f16 + 1ul; +//CHECK: VarDecl {{.*}} f16_ulong '_Float16':'_Float16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1 +auto f16_llong = 1.0f16 + 1ll; +//CHECK: VarDecl {{.*}} f16_llong '_Float16':'_Float16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'long long' 1 +auto f16_ullong = 1.0f16 + 1ull; +//CHECK: VarDecl {{.*}} f16_ullong '_Float16':'_Float16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long long' 1 +auto f16_bool = 1.0f16 + true; +//CHECK: VarDecl {{.*}} f16_bool '_Float16':'_Float16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '_Float16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '_Float16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +//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(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':'float' cinit +//CHECK-NEXT: BinaryOperator {{.*}} 'float' '+' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +//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':'double' cinit +//CHECK-NEXT: BinaryOperator {{.*}} 'double' '+' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' +//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':'long double' cinit +//CHECK-NEXT: BinaryOperator {{.*}} 'long double' '+' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' +//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':'__bf16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +auto bf16_uint = 1.0bf16 + 1u; +//CHECK: VarDecl {{.*}} bf16_uint '__bf16':'__bf16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1 +auto bf16_long = 1.0bf16 + 1l; +//CHECK: VarDecl {{.*}} bf16_long '__bf16':'__bf16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'long' 1 +auto bf16_ulong = 1.0bf16 + 1ul; +//CHECK: VarDecl {{.*}} bf16_ulong '__bf16':'__bf16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1 +auto bf16_llong = 1.0bf16 + 1ll; +//CHECK: VarDecl {{.*}} bf16_llong '__bf16':'__bf16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'long long' 1 +auto bf16_ullong = 1.0bf16 + 1ull; +//CHECK: VarDecl {{.*}} bf16_ullong '__bf16':'__bf16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' +//CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long long' 1 +auto bf16_bool = 1.0bf16 + true; +//CHECK: VarDecl {{.*}} bf16_bool '__bf16':'__bf16' cinit +//CHECK-NEXT: BinaryOperator {{.*}} '__bf16' '+' +//CHECK-NEXT: FloatingLiteral {{.*}} '__bf16' 1.000000e+00 +//CHECK-NEXT: ImplicitCastExpr {{.*}} '__bf16' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +//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))' +//CHECK-NEXT: DeclRefExpr {{.*}} 'int (decltype(0.BF16))' lvalue Function {{.*}} 'f' 'int (decltype(0.BF16))' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' +//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)' +//CHECK-NEXT: DeclRefExpr {{.*}} 'int (_Float16)' lvalue Function {{.*}} 'f' 'int (_Float16)' +//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' +//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)' +//CHECK-NEXT: DeclRefExpr {{.*}} 'int (float)' lvalue Function {{.*}} 'f' 'int (float)' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +//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)' +//CHECK-NEXT: DeclRefExpr {{.*}} 'int (double)' lvalue Function {{.*}} 'f' 'int (double)' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' +//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)' +//CHECK-NEXT: DeclRefExpr {{.*}} 'int (long double)' lvalue Function {{.*}} 'f' 'int (long double)' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' +//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)' +//CHECK-NEXT: DeclRefExpr {{.*}} 'int (int)' lvalue Function {{.*}} 'f' 'int (int)' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +//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)' +//CHECK-NEXT: DeclRefExpr {{.*}} 'int (long double)' lvalue Function {{.*}} 'f_2' 'int (long double)' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +//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)' +//CHECK-NEXT: DeclRefExpr {{.*}} 'int (long double)' lvalue Function {{.*}} 'f_2' 'int (long double)' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' +//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)' +//CHECK-NEXT: DeclRefExpr {{.*}} 'int (long double)' lvalue Function {{.*}} 'f_2' 'int (long double)' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'decltype(0.BF16)':'__bf16' +//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)' +//CHECK-NEXT: DeclRefExpr {{.*}} 'int (long double)' lvalue Function {{.*}} 'f_2' 'int (long double)' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' +//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' +//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(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' +//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'decltype(0.BF16)':'__bf16' +//CHECK-NEXT: MemberExpr {{.*}} '' .operator __bf16 {{.*}} +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue +//CHECK-NEXT: DeclRefExpr {{.*}} 'S':'S' lvalue Var {{.*}} 'user_defined_val' 'S':'S' +_Float16 f16_val(user_defined_val); // calls operator _Float16() +//CHECK: VarDecl {{.*}} f16_val '_Float16' callinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} '_Float16' +//CHECK-NEXT: CXXMemberCallExpr {{.*}} '_Float16 +//CHECK-NEXT: MemberExpr {{.*}} '' .operator _Float16 {{.*}} +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue +//CHECK-NEXT: DeclRefExpr {{.*}} 'S':'S' lvalue Var {{.*}} 'user_defined_val' 'S':'S' +float f_val(user_defined_val); // calls operator float() +//CHECK: VarDecl {{.*}} f_val 'float' callinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'float' +//CHECK-NEXT: MemberExpr {{.*}} '' .operator float {{.*}} +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue +//CHECK-NEXT: DeclRefExpr {{.*}} 'S':'S' lvalue Var {{.*}} 'user_defined_val' 'S':'S' +double d_val(user_defined_val); // calls operator double() +//CHECK: VarDecl {{.*}} d_val 'double' callinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' +//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'double' +//CHECK-NEXT: MemberExpr {{.*}} '' .operator double {{.*}} +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue +//CHECK-NEXT: DeclRefExpr {{.*}} 'S':'S' lvalue Var {{.*}} 'user_defined_val' 'S':'S' +long double ld_val(user_defined_val); // calls operator long double() +//CHECK: VarDecl {{.*}} ld_val 'long double' callinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'long double' +//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'long double' +//CHECK-NEXT: MemberExpr {{.*}} '' .operator long double {{.*}} +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue +//CHECK-NEXT: DeclRefExpr {{.*}} 'S':'S' lvalue Var {{.*}} 'user_defined_val' 'S':'S' +int i_val(user_defined_val); // calls operator int() +//CHECK: VarDecl {{.*}} i_val 'int' callinit +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'int' +//CHECK-NEXT: MemberExpr {{.*}} '' .operator int {{.*}} +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S' lvalue +//CHECK-NEXT: DeclRefExpr {{.*}} 'S':'S' lvalue Var {{.*}} 'user_defined_val' 'S':'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' +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +//CHECK-NEXT: CXXMemberCallExpr {{.*}} 'int' +//CHECK-NEXT: MemberExpr {{.*}} '' .operator int {{.*}} +//CHECK-NEXT: ImplicitCastExpr {{.*}} 'const S1' lvalue +//CHECK-NEXT: DeclRefExpr {{.*}} 'S1':'S1' lvalue Var {{.*}} 'user_defined_val_2' 'S1':'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}}