[clang] [llvm] Dfp (PR #74604)

Zahira Ammarguellat via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 6 07:26:37 PST 2023


https://github.com/zahiraam created https://github.com/llvm/llvm-project/pull/74604

None

>From 707f1625a626faae14b8e24f7e3cf10a2ed621ce Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom at honermann.net>
Date: Sun, 24 Sep 2023 22:38:01 -0400
Subject: [PATCH 1/5] [clang][DFP] Add basic builtin type representation for
 decimal floating point types.

This change adds basic type representation support for the decimal
floating point types defined by ISO/IEC TS 18661-2 and adopted for C23.
These types will also serve as the underlying native types for the
library types defined by ISO/IEC TR 24733 and as implemented in
libstdcxx. This change does not include representation support in
LLVM IR, in debugging information, or in C++ mangling for the MS ABI;
such support will be added in later patches.
---
 clang/include/clang/AST/ASTContext.h          |  2 ++
 clang/include/clang/AST/BuiltinTypes.def      | 17 ++++++++++++++++
 clang/include/clang/Basic/TargetInfo.h        | 17 ++++++++++++++++
 clang/include/clang/Basic/TokenKinds.def      |  4 +++-
 .../include/clang/Serialization/ASTBitCodes.h |  9 +++++++++
 clang/lib/AST/ASTContext.cpp                  | 20 +++++++++++++++++++
 clang/lib/AST/ExprConstant.cpp                |  2 ++
 clang/lib/AST/ItaniumMangle.cpp               |  9 +++++++++
 clang/lib/AST/MicrosoftMangle.cpp             |  6 ++++++
 clang/lib/AST/NSAPI.cpp                       |  3 +++
 clang/lib/AST/PrintfFormatString.cpp          |  4 ++++
 clang/lib/AST/Type.cpp                        |  7 +++++++
 clang/lib/AST/TypeLoc.cpp                     |  3 +++
 clang/lib/Basic/TargetInfo.cpp                |  5 +++++
 clang/lib/CodeGen/CGDebugInfo.cpp             |  7 +++++++
 clang/lib/CodeGen/CodeGenTypes.cpp            |  8 ++++++++
 clang/lib/CodeGen/ItaniumCXXABI.cpp           |  3 +++
 clang/lib/Index/USRGeneration.cpp             |  6 ++++++
 clang/lib/Sema/SemaType.cpp                   | 16 ++++++++++++++-
 clang/lib/Serialization/ASTCommon.cpp         |  9 +++++++++
 clang/lib/Serialization/ASTReader.cpp         |  9 +++++++++
 clang/test/Sema/types.c                       |  4 +++-
 clang/tools/libclang/CIndex.cpp               |  1 +
 23 files changed, 168 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 4ee32c76a95d8..f862456797b5f 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1098,6 +1098,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
   CanQualType SatShortFractTy, SatFractTy, SatLongFractTy;
   CanQualType SatUnsignedShortFractTy, SatUnsignedFractTy,
       SatUnsignedLongFractTy;
+  // ISO/IEC TS 18661-2, ISO/IEC TR 24733, and C23 decimal floating-point.
+  CanQualType DecimalFloat32Ty, DecimalFloat64Ty, DecimalFloat128Ty;
   CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON
   CanQualType BFloat16Ty;
   CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def
index c04f6f6f12719..3a0f78fb6a33f 100644
--- a/clang/include/clang/AST/BuiltinTypes.def
+++ b/clang/include/clang/AST/BuiltinTypes.def
@@ -44,6 +44,10 @@
 #define FLOATING_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
 #endif
 
+#ifndef DECIMAL_FLOATING_TYPE
+#define DECIMAL_FLOATING_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
+#endif
+
 #ifndef PLACEHOLDER_TYPE
 #define PLACEHOLDER_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
 #endif
@@ -221,6 +225,18 @@ FLOATING_TYPE(Float128, Float128Ty)
 // '__ibm128'
 FLOATING_TYPE(Ibm128, Ibm128Ty)
 
+//===- Decimal floating point types ---------------------------------------===//
+// ISO/IEC TS 18661-2, ISO/IEC TR 24733, and C23 decimal floating-point.
+
+// '_Decimal32'
+DECIMAL_FLOATING_TYPE(DecimalFloat32, DecimalFloat32Ty)
+
+// '_Decimal64'
+DECIMAL_FLOATING_TYPE(DecimalFloat64, DecimalFloat64Ty)
+
+// '_Decimal128'
+DECIMAL_FLOATING_TYPE(DecimalFloat128, DecimalFloat128Ty)
+
 //===- Language-specific types --------------------------------------------===//
 
 // This is the type of C++0x 'nullptr'.
@@ -336,6 +352,7 @@ LAST_BUILTIN_TYPE(OMPIterator)
 #undef SHARED_SINGLETON_TYPE
 #undef PLACEHOLDER_TYPE
 #undef FLOATING_TYPE
+#undef DECIMAL_FLOATING_TYPE
 #undef SIGNED_TYPE
 #undef UNSIGNED_TYPE
 #undef BUILTIN_TYPE
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 61be52149341f..ddf166c971fec 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -95,6 +95,11 @@ struct TransferrableTargetInfo {
   unsigned char LongLongWidth, LongLongAlign;
   unsigned char Int128Align;
 
+  // Decimal floating-point bit widths and alignment.
+  unsigned char DecimalFloat32Width, DecimalFloat32Align;
+  unsigned char DecimalFloat64Width, DecimalFloat64Align;
+  unsigned char DecimalFloat128Width, DecimalFloat128Align;
+
   // Fixed point bit widths
   unsigned char ShortAccumWidth, ShortAccumAlign;
   unsigned char AccumWidth, AccumAlign;
@@ -500,6 +505,18 @@ class TargetInfo : public TransferrableTargetInfo,
   /// getInt128Align() - Returns the alignment of Int128.
   unsigned getInt128Align() const { return Int128Align; }
 
+  /// DecimalFloat32Width/Align - Return the size/align of '_Decimal32'.
+  unsigned getDecimalFloat32Width() const { return DecimalFloat32Width; }
+  unsigned getDecimalFloat32Align() const { return DecimalFloat32Align; }
+
+  /// DecimalFloat64Width/Align - Return the size/align of '_Decimal64'.
+  unsigned getDecimalFloat64Width() const { return DecimalFloat64Width; }
+  unsigned getDecimalFloat64Align() const { return DecimalFloat64Align; }
+
+  /// DecimalFloat128Width/Align - Return the size/align of '_Decimal128'.
+  unsigned getDecimalFloat128Width() const { return DecimalFloat128Width; }
+  unsigned getDecimalFloat128Align() const { return DecimalFloat128Align; }
+
   /// getShortAccumWidth/Align - Return the size of 'signed short _Accum' and
   /// 'unsigned short _Accum' for this target, in bits.
   unsigned getShortAccumWidth() const { return ShortAccumWidth; }
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 72e8df8c793a7..fdbeaddd9ab9c 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -427,10 +427,12 @@ KEYWORD(_Accum                      , KEYNOCXX)
 KEYWORD(_Fract                      , KEYNOCXX)
 KEYWORD(_Sat                        , KEYNOCXX)
 
-// GNU Extensions (in impl-reserved namespace)
+// ISO/IEC TS 18661-2, ISO/IEC TR 24733, and C23 decimal floating-point.
 KEYWORD(_Decimal32                  , KEYALL)
 KEYWORD(_Decimal64                  , KEYALL)
 KEYWORD(_Decimal128                 , KEYALL)
+
+// GNU Extensions (in impl-reserved namespace)
 KEYWORD(__null                      , KEYCXX)
 // __alignof returns the preferred alignment of a type, the alignment
 // clang will attempt to give an object of the type if allowed by ABI.
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 9e115f2a5cce3..e83c8cafcac36 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1079,6 +1079,15 @@ enum PredefinedTypeIDs {
   /// \brief The '__ibm128' type
   PREDEF_TYPE_IBM128_ID = 74,
 
+  /// \brief The '_Decimal32' type
+  PREDEF_TYPE_DECIMAL32_ID = 75,
+
+  /// \brief The '_Decimal64' type
+  PREDEF_TYPE_DECIMAL64_ID = 76,
+
+  /// \brief The '_Decimal128' type
+  PREDEF_TYPE_DECIMAL128_ID = 77,
+
 /// OpenCL image types with auto numeration
 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix)                   \
   PREDEF_TYPE_##Id##_ID,
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 4b1d9e86797b7..1a411232cab9d 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1311,6 +1311,11 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
   InitBuiltinType(SatUnsignedFractTy,      BuiltinType::SatUFract);
   InitBuiltinType(SatUnsignedLongFractTy,  BuiltinType::SatULongFract);
 
+  // ISO/IEC TS 18661-2, ISO/IEC TR 24733, and C23 decimal floating-point.
+  InitBuiltinType(DecimalFloat32Ty, BuiltinType::DecimalFloat32);
+  InitBuiltinType(DecimalFloat64Ty, BuiltinType::DecimalFloat64);
+  InitBuiltinType(DecimalFloat128Ty, BuiltinType::DecimalFloat128);
+
   // GNU extension, 128-bit integers.
   InitBuiltinType(Int128Ty,            BuiltinType::Int128);
   InitBuiltinType(UnsignedInt128Ty,    BuiltinType::UInt128);
@@ -2114,6 +2119,18 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
       Width = Target->getLongFractWidth();
       Align = Target->getLongFractAlign();
       break;
+    case BuiltinType::DecimalFloat32:
+      Width = Target->getDecimalFloat32Width();
+      Align = Target->getDecimalFloat32Align();
+      break;
+    case BuiltinType::DecimalFloat64:
+      Width = Target->getDecimalFloat64Width();
+      Align = Target->getDecimalFloat64Align();
+      break;
+    case BuiltinType::DecimalFloat128:
+      Width = Target->getDecimalFloat128Width();
+      Align = Target->getDecimalFloat128Align();
+      break;
     case BuiltinType::BFloat16:
       if (Target->hasBFloat16Type()) {
         Width = Target->getBFloat16Width();
@@ -8066,6 +8083,9 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C,
     case BuiltinType::SatUShortFract:
     case BuiltinType::SatUFract:
     case BuiltinType::SatULongFract:
+    case BuiltinType::DecimalFloat32:
+    case BuiltinType::DecimalFloat64:
+    case BuiltinType::DecimalFloat128:
       // FIXME: potentially need @encodes for these!
       return ' ';
 
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index fea06b97259fe..b048ef1c2c442 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -11416,6 +11416,8 @@ EvaluateBuiltinClassifyType(QualType T, const LangOptions &LangOpts) {
     case BuiltinType::ID: return GCCTypeClass::Integer;
 #define FLOATING_TYPE(ID, SINGLETON_ID) \
     case BuiltinType::ID: return GCCTypeClass::RealFloat;
+#define DECIMAL_FLOATING_TYPE(ID, SINGLETON_ID) \
+    case BuiltinType::ID: return GCCTypeClass::RealFloat;
 #define PLACEHOLDER_TYPE(ID, SINGLETON_ID) \
     case BuiltinType::ID: break;
 #include "clang/AST/BuiltinTypes.def"
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 53963d2a91752..7641f44d72254 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3165,6 +3165,15 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
   case BuiltinType::NullPtr:
     Out << "Dn";
     break;
+  case BuiltinType::DecimalFloat32:
+    Out << "Df";
+    break;
+  case BuiltinType::DecimalFloat64:
+    Out << "Dd";
+    break;
+  case BuiltinType::DecimalFloat128:
+    Out << "De";
+    break;
 
 #define BUILTIN_TYPE(Id, SingletonId)
 #define PLACEHOLDER_TYPE(Id, SingletonId) \
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 79175c79de96b..0e68e6acf6291 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -2408,6 +2408,9 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
   //                 ::= _U # char32_t
   //                 ::= _W # wchar_t
   //                 ::= _Z # __float80 (Digital Mars)
+  //                 ::= FIXME # _Decimal32
+  //                 ::= FIXME # _Decimal64
+  //                 ::= FIXME # _Decimal128
   switch (T->getKind()) {
   case BuiltinType::Void:
     Out << 'X';
@@ -2588,6 +2591,9 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
   case BuiltinType::SatUFract:
   case BuiltinType::SatULongFract:
   case BuiltinType::Ibm128:
+  case BuiltinType::DecimalFloat32:
+  case BuiltinType::DecimalFloat64:
+  case BuiltinType::DecimalFloat128:
   case BuiltinType::Float128: {
     DiagnosticsEngine &Diags = Context.getDiags();
     unsigned DiagID = Diags.getCustomDiagID(
diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp
index 86dee540e9e29..adcae62f81d16 100644
--- a/clang/lib/AST/NSAPI.cpp
+++ b/clang/lib/AST/NSAPI.cpp
@@ -458,6 +458,9 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
   case BuiltinType::Float16:
   case BuiltinType::Float128:
   case BuiltinType::Ibm128:
+  case BuiltinType::DecimalFloat32:
+  case BuiltinType::DecimalFloat64:
+  case BuiltinType::DecimalFloat128:
   case BuiltinType::NullPtr:
   case BuiltinType::ObjCClass:
   case BuiltinType::ObjCId:
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index f0b9d0ecaf234..d7d6bd94c387b 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -783,6 +783,9 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
   case BuiltinType::SatUShortFract:
   case BuiltinType::SatUFract:
   case BuiltinType::SatULongFract:
+  case BuiltinType::DecimalFloat32:
+  case BuiltinType::DecimalFloat64:
+  case BuiltinType::DecimalFloat128:
     // Various types which are non-trivial to correct.
     return false;
 
@@ -805,6 +808,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
 #define SIGNED_TYPE(Id, SingletonId)
 #define UNSIGNED_TYPE(Id, SingletonId)
 #define FLOATING_TYPE(Id, SingletonId)
+#define DECIMAL_FLOATING_TYPE(Id, SingletonId)
 #define BUILTIN_TYPE(Id, SingletonId) \
   case BuiltinType::Id:
 #include "clang/AST/BuiltinTypes.def"
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index c08ebfb7f142b..91de51add303e 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3250,6 +3250,12 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
     return "__float128";
   case Ibm128:
     return "__ibm128";
+  case DecimalFloat32:
+    return "_Decimal32";
+  case DecimalFloat64:
+    return "_Decimal64";
+  case DecimalFloat128:
+    return "_Decimal128";
   case WChar_S:
   case WChar_U:
     return Policy.MSWChar ? "__wchar_t" : "wchar_t";
@@ -4434,6 +4440,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
 #define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
 #define UNSIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
 #define FLOATING_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define DECIMAL_FLOATING_TYPE(Id, SingletonId) case BuiltinType::Id:
 #define BUILTIN_TYPE(Id, SingletonId)
 #include "clang/AST/BuiltinTypes.def"
       return false;
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index e12b9b50f6e72..8556488ab67dc 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -393,6 +393,9 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
   case BuiltinType::SatUFract:
   case BuiltinType::SatULongFract:
   case BuiltinType::BFloat16:
+  case BuiltinType::DecimalFloat32:
+  case BuiltinType::DecimalFloat64:
+  case BuiltinType::DecimalFloat128:
     llvm_unreachable("Builtin type needs extra local data!");
     // Fall through, if the impossible happens.
 
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 6cd5d618a4aca..5cd7e259db90d 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -75,6 +75,11 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
   LongLongWidth = LongLongAlign = 64;
   Int128Align = 128;
 
+  // Decimal floating-point default bit widths and alignment.
+  DecimalFloat32Width = DecimalFloat32Align = 32;
+  DecimalFloat64Width = DecimalFloat64Align = 64;
+  DecimalFloat128Width = DecimalFloat128Align = 128;
+
   // Fixed point default bit widths
   ShortAccumWidth = ShortAccumAlign = 16;
   AccumWidth = AccumAlign = 32;
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 36e29285141b5..283d7bb4645b9 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -46,6 +46,7 @@
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MD5.h"
 #include "llvm/Support/Path.h"
@@ -929,6 +930,12 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
   case BuiltinType::SatULongFract:
     Encoding = llvm::dwarf::DW_ATE_unsigned_fixed;
     break;
+  case BuiltinType::DecimalFloat32:
+  case BuiltinType::DecimalFloat64:
+  case BuiltinType::DecimalFloat128:
+    llvm::report_fatal_error("DWARF debugging support for decimal floating "
+                             "point is not yet implemented");
+    break;
   }
 
   BTName = BT->getName(CGM.getLangOpts());
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 30021794a0bb3..9ec3d30968445 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -25,6 +25,7 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Support/Error.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -417,6 +418,13 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
                                     /* UseNativeHalf = */ false);
       break;
 
+    case BuiltinType::DecimalFloat32:
+    case BuiltinType::DecimalFloat64:
+    case BuiltinType::DecimalFloat128:
+      llvm::report_fatal_error("LLVM type support for decimal floating point "
+                               "is not yet implemented");
+      break;
+
     case BuiltinType::NullPtr:
       // Model std::nullptr_t as i8*
       ResultType = llvm::Type::getInt8PtrTy(getLLVMContext());
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 385dcf21f724e..797103257ed89 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3342,6 +3342,9 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
     case BuiltinType::Char32:
     case BuiltinType::Int128:
     case BuiltinType::UInt128:
+    case BuiltinType::DecimalFloat32:
+    case BuiltinType::DecimalFloat64:
+    case BuiltinType::DecimalFloat128:
       return true;
 
 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp
index f778a6208d512..4ab9370e8a804 100644
--- a/clang/lib/Index/USRGeneration.cpp
+++ b/clang/lib/Index/USRGeneration.cpp
@@ -803,6 +803,12 @@ void USRGenerator::VisitType(QualType T) {
           Out << "@BT at __bf16"; break;
         case BuiltinType::Ibm128:
           Out << "@BT at __ibm128"; break;
+        case BuiltinType::DecimalFloat32:
+          Out << "@BT at _Decimal32"; break;
+        case BuiltinType::DecimalFloat64:
+          Out << "@BT at _Decimal64"; break;
+        case BuiltinType::DecimalFloat128:
+          Out << "@BT at _Decimal128"; break;
         case BuiltinType::ObjCId:
           Out << 'o'; break;
         case BuiltinType::ObjCClass:
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index ffd29446b4f2e..fa515dd3bc935 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1272,6 +1272,20 @@ TSTToUnaryTransformType(DeclSpec::TST SwitchTST) {
   }
 }
 
+static CanQualType
+TSTToDecimalFloatType(ASTContext &Context, DeclSpec::TST SwitchTST) {
+  switch (SwitchTST) {
+  case DeclSpec::TST_decimal32:
+    return Context.DecimalFloat32Ty;
+  case DeclSpec::TST_decimal64:
+    return Context.DecimalFloat64Ty;
+  case DeclSpec::TST_decimal128:
+    return Context.DecimalFloat128Ty;
+  default:
+    llvm_unreachable("expected a decimal floating point type specifier type");
+  }
+}
+
 /// Convert the specified declspec to the appropriate type
 /// object.
 /// \param state Specifies the declarator containing the declaration specifier
@@ -1575,7 +1589,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
   case DeclSpec::TST_decimal64:    // _Decimal64
   case DeclSpec::TST_decimal128:   // _Decimal128
     S.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported);
-    Result = Context.IntTy;
+    Result = TSTToDecimalFloatType(Context, DS.getTypeSpecType());
     declarator.setInvalidType(true);
     break;
   case DeclSpec::TST_class:
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index 72e5821074809..17abf2188af9a 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -273,6 +273,15 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
   case BuiltinType::BFloat16:
     ID = PREDEF_TYPE_BFLOAT16_ID;
     break;
+  case BuiltinType::DecimalFloat32:
+    ID = PREDEF_TYPE_DECIMAL32_ID;
+    break;
+  case BuiltinType::DecimalFloat64:
+    ID = PREDEF_TYPE_DECIMAL64_ID;
+    break;
+  case BuiltinType::DecimalFloat128:
+    ID = PREDEF_TYPE_DECIMAL128_ID;
+    break;
   }
 
   return TypeIdx(ID);
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 0952244d037a7..9d6a018177b09 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -7276,6 +7276,15 @@ QualType ASTReader::GetType(TypeID ID) {
     case PREDEF_TYPE_OMP_ITERATOR:
       T = Context.OMPIteratorTy;
       break;
+    case PREDEF_TYPE_DECIMAL32_ID:
+      T = Context.DecimalFloat32Ty;
+      break;
+    case PREDEF_TYPE_DECIMAL64_ID:
+      T = Context.DecimalFloat64Ty;
+      break;
+    case PREDEF_TYPE_DECIMAL128_ID:
+      T = Context.DecimalFloat128Ty;
+      break;
 #define SVE_TYPE(Name, Id, SingletonId) \
     case PREDEF_TYPE_##Id##_ID: \
       T = Context.SingletonId; \
diff --git a/clang/test/Sema/types.c b/clang/test/Sema/types.c
index e0a6ba4f0691b..4ce8d5ffffb76 100644
--- a/clang/test/Sema/types.c
+++ b/clang/test/Sema/types.c
@@ -48,7 +48,9 @@ enum e { e_1 };
 extern int j[sizeof(enum e)];  // expected-note {{previous declaration}}
 int j[42];   // expected-error {{redefinition of 'j' with a different type: 'int[42]' vs 'int[4]'}}
 
-_Decimal32 x;  // expected-error {{GNU decimal type extension not supported}}
+_Decimal32 d32; // expected-error {{GNU decimal type extension not supported}}
+_Decimal64 d64; // expected-error {{GNU decimal type extension not supported}}
+_Decimal128 d128; // expected-error {{GNU decimal type extension not supported}}
 
 int __attribute__ ((vector_size (8), vector_size (8))) v;  // expected-error {{invalid vector element type}}
 
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index f0c8ecfcb6264..e9d97d5502823 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -1645,6 +1645,7 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
 #define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
 #define UNSIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
 #define FLOATING_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define DECIMAL_FLOATING_TYPE(Id, SingletonId) case BuiltinType::Id:
 #define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
 #include "clang/AST/BuiltinTypes.def"
     break;

>From f06fce6d01508456a91dc702d4a92e313bc06f47 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom at honermann.net>
Date: Wed, 4 Oct 2023 09:58:48 -0400
Subject: [PATCH 2/5] [clang][DFP] Add support for
 -fexperimental-decimal-floating-point.

Though the ISO/IEC TS 18661-2:2015 decimal floating-point (DFP)
extension has been adopted for the upcoming C23 standard, it will
remain necessary to be able to explicitly enable and disable support
for the extension for the foreseeable future for use with previous
C standards and with C++. This change adds a driver and cc1 option
to enable language support. Since support for the feature is not yet
complete, the option name explicitly reflects its status as
experimental and only serves to enable testing at this point.

No target considerations have been implemented yet. The option only
serves to enable the _Decimal32, _Decimal64, and _Decimal128 keywords
to be used as DFP type specifiers in C; these keywords are not enabled
for C++ since, per ISO/IEC TR 24733:2011 and the gcc implementation,
DFP support in C++ is provided via standard library types (that are
expected to wrap a builtin type exposed by other means).

The C23 standard specifies that the __STDC_IEC_60559_DFP__ macro be
predefined when the DFP extensions are available. This change adds
that macro with a placeholder value for use in testing.
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 +--
 clang/include/clang/Basic/LangOptions.def     |  3 ++
 clang/include/clang/Basic/TokenKinds.def      |  6 ++--
 clang/include/clang/Driver/Options.td         |  5 +++
 clang/lib/Driver/ToolChains/Clang.cpp         |  3 ++
 clang/lib/Frontend/InitPreprocessor.cpp       |  6 ++++
 clang/lib/Sema/SemaType.cpp                   | 10 ++++--
 clang/test/Driver/dfp-enablement-lang.c       | 36 +++++++++++++++++++
 clang/test/Sema/dfp-types.c                   |  9 +++++
 clang/test/Sema/types.c                       |  6 ++--
 10 files changed, 77 insertions(+), 11 deletions(-)
 create mode 100644 clang/test/Driver/dfp-enablement-lang.c
 create mode 100644 clang/test/Sema/dfp-types.c

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0ac4df8edb242..d5c798b658e72 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10232,8 +10232,8 @@ def ext_missing_type_specifier : ExtWarn<
   "implicit int">, InGroup<ImplicitInt>, DefaultError;
 def err_missing_type_specifier : Error<
   "a type specifier is required for all declarations">;
-def err_decimal_unsupported : Error<
-  "GNU decimal type extension not supported">;
+def err_dfp_disabled : Error<
+  "decimal floating-point extensions are not enabled">;
 def err_objc_array_of_interfaces : Error<
   "array of interface %0 is invalid (probably should be an array of pointers)">;
 def ext_c99_array_usage : Extension<
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index e18b5b80a34e7..2902c4d891c5a 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -427,6 +427,9 @@ LANGOPT(FixedPoint, 1, 0, "fixed point types")
 LANGOPT(PaddingOnUnsignedFixedPoint, 1, 0,
         "unsigned fixed point types having one extra padding bit")
 
+// ISO/IEC TS 18661-2, ISO/IEC TR 24733, and C23 decimal floating-point.
+LANGOPT(DecimalFloatingPoint, 1, 0, "decimal floating-point extensions")
+
 LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors")
 
 LANGOPT(RegCall4, 1, 0, "Set __regcall4 as a default calling convention to respect __regcall ABI v.4")
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index fdbeaddd9ab9c..12f80e38ded9b 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -428,9 +428,9 @@ KEYWORD(_Fract                      , KEYNOCXX)
 KEYWORD(_Sat                        , KEYNOCXX)
 
 // ISO/IEC TS 18661-2, ISO/IEC TR 24733, and C23 decimal floating-point.
-KEYWORD(_Decimal32                  , KEYALL)
-KEYWORD(_Decimal64                  , KEYALL)
-KEYWORD(_Decimal128                 , KEYALL)
+KEYWORD(_Decimal32                  , KEYNOCXX)
+KEYWORD(_Decimal64                  , KEYNOCXX)
+KEYWORD(_Decimal128                 , KEYNOCXX)
 
 // GNU Extensions (in impl-reserved namespace)
 KEYWORD(__null                      , KEYCXX)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 553c7928c4f94..8a510295d3441 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2055,6 +2055,11 @@ defm fixed_point : BoolFOption<"fixed-point",
   PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">,
   NegFlag<SetFalse, [], [ClangOption], "Disable">,
   BothFlags<[], [ClangOption], " fixed point types">>, ShouldParseIf<!strconcat("!", cplusplus.KeyPath)>;
+defm decimal_floating_point : BoolFOption<"experimental-decimal-floating-point",
+  LangOpts<"DecimalFloatingPoint">, DefaultFalse,
+  PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">,
+  NegFlag<SetFalse, [], [ClangOption], "Disable">,
+  BothFlags<[], [ClangOption], " decimal floating-point extensions">>;
 defm cxx_static_destructors : BoolFOption<"c++-static-destructors",
   LangOpts<"RegisterStaticDestructors">, DefaultTrue,
   NegFlag<SetFalse, [], [ClangOption, CC1Option],
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 40e60585a8b8d..d98574def75de 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6004,6 +6004,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.addOptInFlag(CmdArgs, options::OPT_ffixed_point,
                     options::OPT_fno_fixed_point);
 
+  Args.addOptInFlag(CmdArgs, options::OPT_fdecimal_floating_point,
+                    options::OPT_fno_decimal_floating_point);
+
   if (Arg *A = Args.getLastArg(options::OPT_fcxx_abi_EQ))
     A->render(Args, CmdArgs);
 
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index e5db8a654e670..ffa0eccce59b5 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -498,6 +498,12 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
   Builder.defineMacro("__STDC_UTF_16__", "1");
   Builder.defineMacro("__STDC_UTF_32__", "1");
 
+  // C23 decimal floating point extensions.
+  // FIXME: Define to 202311L when support for C23 decimal floating point
+  // FIXME: extensions is feature complete.
+  if (!LangOpts.CPlusPlus && LangOpts.DecimalFloatingPoint)
+    Builder.defineMacro("__STDC_IEC_60559_DFP__", "197001L");
+
   if (LangOpts.ObjC)
     Builder.defineMacro("__OBJC__");
 
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index fa515dd3bc935..c3ab0d000f4d3 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1588,9 +1588,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
   case DeclSpec::TST_decimal32:    // _Decimal32
   case DeclSpec::TST_decimal64:    // _Decimal64
   case DeclSpec::TST_decimal128:   // _Decimal128
-    S.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported);
-    Result = TSTToDecimalFloatType(Context, DS.getTypeSpecType());
-    declarator.setInvalidType(true);
+    if (!S.getLangOpts().DecimalFloatingPoint) {
+      S.Diag(DS.getTypeSpecTypeLoc(), diag::err_dfp_disabled);
+      Result = Context.IntTy;
+      declarator.setInvalidType(true);
+    } else {
+      Result = TSTToDecimalFloatType(Context, DS.getTypeSpecType());
+    }
     break;
   case DeclSpec::TST_class:
   case DeclSpec::TST_enum:
diff --git a/clang/test/Driver/dfp-enablement-lang.c b/clang/test/Driver/dfp-enablement-lang.c
new file mode 100644
index 0000000000000..fe566e6cef848
--- /dev/null
+++ b/clang/test/Driver/dfp-enablement-lang.c
@@ -0,0 +1,36 @@
+// This test is intended to validate whether decimal floating-point (DFP)
+// extensions are enabled based on language standard and to ensure a proper
+// diagnostic is issued for any use of DFP features otherwise.
+
+// RUN: %clang -target x86_64-unknown-linux-gnu -std=c17 -fsyntax-only -Xclang -verify=dfp-off,c-dfp-off %s
+// RUN: %clang -target x86_64-unknown-linux-gnu -std=c17 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify %s
+// FIXME: Remove -fexperimental-decimal-floating-point once -std=c23 implies DFP enablement.
+// RUN: %clang -target x86_64-unknown-linux-gnu -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify %s
+// RUN: %clang -target x86_64-unknown-linux-gnu -std=c23 -fsyntax-only -fno-experimental-decimal-floating-point -Xclang -verify=dfp-off,c-dfp-off %s
+// RUN: %clang -target x86_64-unknown-linux-gnu -x c++ -std=c++23 -fsyntax-only -Xclang -verify=cxx,dfp-off %s
+// RUN: %clang -target x86_64-unknown-linux-gnu -x c++ -std=c++23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=cxx %s
+// FIXME: Remove -fexperimental-decimal-floating-point once -std=c++2c (or later) implies DFP enablement.
+// RUN: %clang -target x86_64-unknown-linux-gnu -x c++ -std=c++2c -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=cxx %s
+// RUN: %clang -target x86_64-unknown-linux-gnu -x c++ -std=c++2c -fsyntax-only -fno-experimental-decimal-floating-point -Xclang -verify=cxx,dfp-off %s
+
+// expected-no-diagnostics
+
+#if defined(__cplusplus)
+  #if defined(__STDC_IEC_60559_DFP__)
+    #error __STDC_IEC_60559_DFP__ should never be defined for C++
+  #endif
+#else
+  #if !defined(__STDC_IEC_60559_DFP__)
+    // c-dfp-off-error at +1 {{__STDC_IEC_60559_DFP__ should be defined}}
+    #error __STDC_IEC_60559_DFP__ should be defined for C when DFP support is enabled
+  #elif __STDC_IEC_60559_DFP__ != 197001L
+    #error __STDC_IEC_60559_DFP__ has the wrong value
+  #endif
+#endif
+
+_Decimal32 d32;   // cxx-error {{unknown type name '_Decimal32'}} \
+                  // c-dfp-off-error {{decimal floating-point extensions are not enabled}}
+_Decimal64 d64;   // cxx-error {{unknown type name '_Decimal64'}} \
+                  // c-dfp-off-error {{decimal floating-point extensions are not enabled}}
+_Decimal128 d128; // cxx-error {{unknown type name '_Decimal128'}} \
+                  // c-dfp-off-error {{decimal floating-point extensions are not enabled}}
diff --git a/clang/test/Sema/dfp-types.c b/clang/test/Sema/dfp-types.c
new file mode 100644
index 0000000000000..86bb5ce945ca1
--- /dev/null
+++ b/clang/test/Sema/dfp-types.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c23 -fexperimental-decimal-floating-point -fsyntax-only -verify=c %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -std=c++2c -fexperimental-decimal-floating-point -fsyntax-only -verify=cxx %s
+
+// c-no-diagnostics
+
+// _Decimal32, _Decimal64, and _Decimal128 are never keywords in C++.
+_Decimal32 d32; // cxx-error {{unknown type name '_Decimal32'}}
+_Decimal64 d64; // cxx-error {{unknown type name '_Decimal64'}}
+_Decimal128 d28; // cxx-error {{unknown type name '_Decimal128'}}
diff --git a/clang/test/Sema/types.c b/clang/test/Sema/types.c
index 4ce8d5ffffb76..9f7e1f48d5631 100644
--- a/clang/test/Sema/types.c
+++ b/clang/test/Sema/types.c
@@ -48,9 +48,9 @@ enum e { e_1 };
 extern int j[sizeof(enum e)];  // expected-note {{previous declaration}}
 int j[42];   // expected-error {{redefinition of 'j' with a different type: 'int[42]' vs 'int[4]'}}
 
-_Decimal32 d32; // expected-error {{GNU decimal type extension not supported}}
-_Decimal64 d64; // expected-error {{GNU decimal type extension not supported}}
-_Decimal128 d128; // expected-error {{GNU decimal type extension not supported}}
+_Decimal32 d32; // expected-error {{decimal floating-point extensions are not enabled}}
+_Decimal64 d64; // expected-error {{decimal floating-point extensions are not enabled}}
+_Decimal128 d128; // expected-error {{decimal floating-point extensions are not enabled}}
 
 int __attribute__ ((vector_size (8), vector_size (8))) v;  // expected-error {{invalid vector element type}}
 

>From ef6273c1e72f4b57810a4fa661165fb7c9ecc393 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom at honermann.net>
Date: Mon, 9 Oct 2023 17:58:38 -0400
Subject: [PATCH 3/5] [clang][DFP] Add __attribute__((mode(*D))) support for
 declaring decimal floating-point types.

Current proposals for supporting decimal floating-point (DFP) types in
C++, e.g., ISO/IEC TR 24733:2011, do not specify keywords to be used as
type specifiers. Rather, DFP types are specified as standard library
types that, in practice, wrap a builtin type that is not otherwise
exposed with a simple name. Gcc enables builtin DFP types to be
declared using the GNU mode attribute as follows:
  float __attribute__((mode(SD))) // _Decimal32
  float __attribute__((mode(DD))) // _Decimal64
  float __attribute__((mode(TD))) // _Decimal128
This change implements support for these additional machine modes.

This change also extends several of the clang::Type AST node attributes
to include DFP types in addition to other floating-point types. These
extensions match extensions to terms of the same name made in C23. The
directly affected predicates includes:
  Type::isRealFloatingType()
  Type::isFloatingType()
  Type::isRealType()
  Type::isArithmeticType()
The following new predicate can be used to differentiate DFP types
where needed.
  Type::isDecimalFloatingType()

The existing DFP specifications, including C23, do not include support
for complex DFP types. Gcc does not provide such support either. These
changes follow that existing precedent and do not enable support for
complex DFP types as well. However, vector types are allowed to have
DFP types as their element type.
---
 clang/include/clang/AST/Type.h          | 11 +++-
 clang/include/clang/Basic/TargetInfo.h  | 16 ++++-
 clang/lib/AST/ASTContext.cpp            |  6 ++
 clang/lib/AST/Type.cpp                  | 12 +++-
 clang/lib/Basic/TargetInfo.cpp          |  3 +
 clang/lib/Sema/SemaChecking.cpp         |  9 ++-
 clang/lib/Sema/SemaDeclAttr.cpp         | 14 ++++
 clang/test/Driver/dfp-enablement-lang.c |  8 +++
 clang/test/Sema/dfp-types.c             | 87 +++++++++++++++++++++++--
 clang/test/SemaCXX/dfp-types.cpp        | 14 ++++
 10 files changed, 169 insertions(+), 11 deletions(-)
 create mode 100644 clang/test/SemaCXX/dfp-types.cpp

diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 46dbadd8b878b..3fcec7b594abc 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2176,9 +2176,14 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
   bool isUnscopedEnumerationType() const;
 
   /// Floating point categories.
+  bool isDecimalFloatingType() const;
+                                   // C23 6.2.5p13 (_Decimal32/64/128)
   bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)
+                                   // C23 6.2.5p14 (standard + decimal float)
+                                   // C23 H.2.4p5  (+interchange +extended FP)
   /// isComplexType() does *not* include complex integers (a GCC extension).
   /// isComplexIntegerType() can be used to test for complex integers.
+  /// C23 did not add complex decimal floating-point.
   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)
@@ -2746,8 +2751,12 @@ class BuiltinType : public Type {
     return getKind() >= Bool && getKind() <= UInt128;
   }
 
+  bool isDecimalFloatingPoint() const {
+    return getKind() >= DecimalFloat32 && getKind() <= DecimalFloat128;
+  }
+
   bool isFloatingPoint() const {
-    return getKind() >= Half && getKind() <= Ibm128;
+    return getKind() >= Half && getKind() <= DecimalFloat128;
   }
 
   bool isSVEBool() const { return getKind() == Kind::SveBool; }
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index ddf166c971fec..f8734dcda10c7 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -75,9 +75,23 @@ enum class FloatModeKind {
   LongDouble = 1 << 3,
   Float128 = 1 << 4,
   Ibm128 = 1 << 5,
-  LLVM_MARK_AS_BITMASK_ENUM(Ibm128)
+  Decimal32 = 1 << 6,
+  Decimal64 = 1 << 7,
+  Decimal128 = 1 << 8,
+  LLVM_MARK_AS_BITMASK_ENUM(Decimal128)
 };
 
+inline bool isDecimalFloatModeKind(FloatModeKind FMK) {
+  switch (FMK) {
+  case FloatModeKind::Decimal32:
+  case FloatModeKind::Decimal64:
+  case FloatModeKind::Decimal128:
+    return true;
+  default:
+    return false;
+  }
+}
+
 /// Fields controlling how types are laid out in memory; these may need to
 /// be copied for targets like AMDGPU that base their ABIs on an auxiliary
 /// CPU target.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 1a411232cab9d..0aef78b685460 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -12164,6 +12164,12 @@ QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth,
     return Float128Ty;
   case FloatModeKind::Ibm128:
     return Ibm128Ty;
+  case FloatModeKind::Decimal32:
+    return DecimalFloat32Ty;
+  case FloatModeKind::Decimal64:
+    return DecimalFloat64Ty;
+  case FloatModeKind::Decimal128:
+    return DecimalFloat128Ty;
   case FloatModeKind::NoFloat:
     return {};
   }
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 91de51add303e..26d813b160bc3 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2190,7 +2190,7 @@ bool Type::hasUnsignedIntegerRepresentation() const {
 bool Type::isFloatingType() const {
   if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
     return BT->getKind() >= BuiltinType::Half &&
-           BT->getKind() <= BuiltinType::Ibm128;
+           BT->getKind() <= BuiltinType::DecimalFloat128;
   if (const auto *CT = dyn_cast<ComplexType>(CanonicalType))
     return CT->getElementType()->isFloatingType();
   return false;
@@ -2204,6 +2204,12 @@ bool Type::hasFloatingRepresentation() const {
   return isFloatingType();
 }
 
+bool Type::isDecimalFloatingType() const {
+  if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
+    return BT->isDecimalFloatingPoint();
+  return false;
+}
+
 bool Type::isRealFloatingType() const {
   if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
     return BT->isFloatingPoint();
@@ -2213,7 +2219,7 @@ bool Type::isRealFloatingType() const {
 bool Type::isRealType() const {
   if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
     return BT->getKind() >= BuiltinType::Bool &&
-           BT->getKind() <= BuiltinType::Ibm128;
+           BT->getKind() <= BuiltinType::DecimalFloat128;
   if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
       return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
   return isBitIntType();
@@ -2222,7 +2228,7 @@ bool Type::isRealType() const {
 bool Type::isArithmeticType() const {
   if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
     return BT->getKind() >= BuiltinType::Bool &&
-           BT->getKind() <= BuiltinType::Ibm128;
+           BT->getKind() <= BuiltinType::DecimalFloat128;
   if (const auto *ET = dyn_cast<EnumType>(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.
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 5cd7e259db90d..6b34c9e8d33eb 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -319,6 +319,9 @@ TargetInfo::IntType TargetInfo::getLeastIntTypeByWidth(unsigned BitWidth,
 
 FloatModeKind TargetInfo::getRealTypeByWidth(unsigned BitWidth,
                                              FloatModeKind ExplicitType) const {
+  if (isDecimalFloatModeKind(ExplicitType))
+    return ExplicitType;
+
   if (getHalfWidth() == BitWidth)
     return FloatModeKind::Half;
   if (getFloatWidth() == BitWidth)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index fad70223362ed..97f175f770ca3 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -8531,8 +8531,8 @@ bool Sema::SemaBuiltinComplex(CallExpr *TheCall) {
            << Real->getSourceRange() << Imag->getSourceRange();
   }
 
-  // We don't allow _Complex _Float16 nor _Complex __fp16 as type specifiers;
-  // don't allow this builtin to form those types either.
+  // We don't allow _Complex _Float16, _Complex __fp16, or _Complex _DecimalXX
+  // as type specifiers; don't allow this builtin to form those types either.
   // FIXME: Should we allow these types?
   if (Real->getType()->isFloat16Type())
     return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec)
@@ -8540,6 +8540,11 @@ bool Sema::SemaBuiltinComplex(CallExpr *TheCall) {
   if (Real->getType()->isHalfType())
     return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec)
            << "half";
+  if (Real->getType()->isDecimalFloatingType()) {
+    const BuiltinType *BT = Real->getType()->getAs<BuiltinType>();
+    return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec)
+           << BT->getName(Context.getPrintingPolicy());
+  }
 
   TheCall->setType(Context.getComplexType(Real->getType()));
   return false;
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index cc98713241395..cf9c51329577e 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4668,6 +4668,7 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
   IntegerMode = true;
   ComplexMode = false;
   ExplicitType = FloatModeKind::NoFloat;
+  FloatModeKind ExplicitDFPType = FloatModeKind::NoFloat;
   switch (Str.size()) {
   case 2:
     switch (Str[0]) {
@@ -4678,9 +4679,11 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
       DestWidth = 16;
       break;
     case 'S':
+      ExplicitDFPType = FloatModeKind::Decimal32;
       DestWidth = 32;
       break;
     case 'D':
+      ExplicitDFPType = FloatModeKind::Decimal64;
       DestWidth = 64;
       break;
     case 'X':
@@ -4692,6 +4695,7 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
       break;
     case 'T':
       ExplicitType = FloatModeKind::LongDouble;
+      ExplicitDFPType = FloatModeKind::Decimal128;
       DestWidth = 128;
       break;
     case 'I':
@@ -4704,6 +4708,9 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
     } else if (Str[1] == 'C') {
       IntegerMode = false;
       ComplexMode = true;
+    } else if (Str[1] == 'D') {
+      IntegerMode = false;
+      ExplicitType = ExplicitDFPType;
     } else if (Str[1] != 'I') {
       DestWidth = 0;
     }
@@ -4853,6 +4860,13 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
     return;
   }
 
+  if (NewElemTy->isDecimalFloatingType()) {
+    if (!getLangOpts().DecimalFloatingPoint) {
+      Diag(AttrLoc, diag::err_dfp_disabled);
+      return;
+    }
+  }
+
   if (ComplexMode) {
     NewElemTy = Context.getComplexType(NewElemTy);
   }
diff --git a/clang/test/Driver/dfp-enablement-lang.c b/clang/test/Driver/dfp-enablement-lang.c
index fe566e6cef848..05406d653a69f 100644
--- a/clang/test/Driver/dfp-enablement-lang.c
+++ b/clang/test/Driver/dfp-enablement-lang.c
@@ -34,3 +34,11 @@ _Decimal64 d64;   // cxx-error {{unknown type name '_Decimal64'}} \
                   // c-dfp-off-error {{decimal floating-point extensions are not enabled}}
 _Decimal128 d128; // cxx-error {{unknown type name '_Decimal128'}} \
                   // c-dfp-off-error {{decimal floating-point extensions are not enabled}}
+
+typedef float __attribute__((mode(SD))) D32;  // dfp-off-error {{decimal floating-point extensions are not enabled}}
+typedef float __attribute__((mode(DD))) D64;  // dfp-off-error {{decimal floating-point extensions are not enabled}}
+typedef float __attribute__((mode(TD))) D128; // dfp-off-error {{decimal floating-point extensions are not enabled}}
+
+float __attribute__((mode(SD))) famsd; // dfp-off-error {{decimal floating-point extensions are not enabled}}
+float __attribute__((mode(DD))) famdd; // dfp-off-error {{decimal floating-point extensions are not enabled}}
+float __attribute__((mode(TD))) famtd; // dfp-off-error {{decimal floating-point extensions are not enabled}}
diff --git a/clang/test/Sema/dfp-types.c b/clang/test/Sema/dfp-types.c
index 86bb5ce945ca1..330fb898f9414 100644
--- a/clang/test/Sema/dfp-types.c
+++ b/clang/test/Sema/dfp-types.c
@@ -1,9 +1,88 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c23 -fexperimental-decimal-floating-point -fsyntax-only -verify=c %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -std=c++2c -fexperimental-decimal-floating-point -fsyntax-only -verify=cxx %s
-
-// c-no-diagnostics
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c23 -fexperimental-decimal-floating-point -fsyntax-only -verify=expected,c %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -std=c++2c -fexperimental-decimal-floating-point -fsyntax-only -verify=expected,cxx %s
 
 // _Decimal32, _Decimal64, and _Decimal128 are never keywords in C++.
 _Decimal32 d32; // cxx-error {{unknown type name '_Decimal32'}}
 _Decimal64 d64; // cxx-error {{unknown type name '_Decimal64'}}
 _Decimal128 d28; // cxx-error {{unknown type name '_Decimal128'}}
+
+// DFP types are available via the GNU mode attribute in both C and C++.
+typedef float __attribute__((mode(SD))) D32;
+typedef float __attribute__((mode(DD))) D64;
+typedef float __attribute__((mode(TD))) D128;
+
+// The GNU mode attribute requires a floating point base type for DFP types.
+// These are ok.
+long double __attribute((mode(SD))) ldamsd;
+double __attribute((mode(DD))) damdd;
+_Float16 __attribute((mode(SD))) f16amsd;
+__bf16 __attribute((mode(SD))) bf16amsd;
+__float128 __attribute((mode(TD))) f128amtd;
+// These are not ok.
+void __attribute((mode(SD))) vamsd; // expected-error {{type of machine mode does not match type of base type}}
+int __attribute((mode(DD))) iamdd; // expected-error {{type of machine mode does not match type of base type}}
+int* __attribute((mode(TD))) ipamtd; // expected-error {{mode attribute only supported for integer and floating-point types}}
+float __attribute((mode(TD))) *fapmtd; // expected-error {{mode attribute only supported for integer and floating-point types}}
+
+// DFP types may be used as vector elements, but declaration form is restricted.
+float __attribute__((mode(V4SD))) famv4sd; // expected-warning {{deprecated; use the 'vector_size' attribute instead}}
+float __attribute__((mode(SD))) __attribute__((vector_size(16))) famsdv16;
+D64 __attribute__((vector_size(16))) d64av16;
+
+// DFP types are not allowed as elements of complex types.
+D32 _Complex d32c; // expected-error {{'_Complex type-name' is invalid}}
+_Decimal32 _Complex kd32c; // c-error {{'_Complex _Decimal32' is invalid}} \
+                              cxx-error {{unknown type name '_Decimal32'}}
+
+_Static_assert(sizeof(D32) == 4);
+_Static_assert(sizeof(D64) == 8);
+_Static_assert(sizeof(D128) == 16);
+
+_Static_assert(_Alignof(D32) == 4);
+_Static_assert(_Alignof(D64) == 8);
+_Static_assert(_Alignof(D128) == 16);
+
+struct s {
+  D32 d32;
+  D64 d64;
+  D128 d128;
+  union {
+    D32 ud32;
+    D64 ud64;
+    D128 ud128;
+  };
+};
+
+struct bitfield {
+  D32 d32 : 32;    // expected-error {{bit-field 'd32' has non-integral type}}
+  D64 d64 : 64;    // expected-error {{bit-field 'd64' has non-integral type}}
+  D128 d128 : 128; // expected-error {{bit-field 'd128' has non-integral type}}
+};
+
+D32 test_d32(D32 d32) {
+  return d32;
+}
+
+D64 test_d64(D64 d64) {
+  return d64;
+}
+
+D128 test_d128(D128 d128) {
+  return d128;
+}
+
+void test_builtin_complex(D32 d32) {
+  __auto_type lv = __builtin_complex(d32, d32); // expected-error {{'_Complex _Decimal32' is invalid}}
+}
+
+void test_generic(D32 d32, D64 d64, D128 d128) {
+  (void)_Generic(d32,  D64 : 0, D128 : 0); // expected-error-re {{controlling expression type {{.*}} not compatible with any generic association type}}
+  (void)_Generic(d64,  D32 : 0, D128 : 0); // expected-error-re {{controlling expression type {{.*}} not compatible with any generic association type}}
+  (void)_Generic(d128, D32 : 0, D64  : 0); // expected-error-re {{controlling expression type {{.*}} not compatible with any generic association type}}
+  _Static_assert(_Generic(d32,  D64 : 0, D128 : 0, default : 1) == 1);
+  _Static_assert(_Generic(d64,  D32 : 0, D128 : 0, default : 1) == 1);
+  _Static_assert(_Generic(d128, D32 : 0, D64  : 0, default : 1) == 1);
+  _Static_assert(_Generic(d32,  D32 : 1, D64  : 0, D128 : 0) == 1);
+  _Static_assert(_Generic(d64,  D32 : 0, D64  : 1, D128 : 0) == 1);
+  _Static_assert(_Generic(d128, D32 : 0, D64  : 0, D128 : 1) == 1);
+}
diff --git a/clang/test/SemaCXX/dfp-types.cpp b/clang/test/SemaCXX/dfp-types.cpp
new file mode 100644
index 0000000000000..9a26aefab20f6
--- /dev/null
+++ b/clang/test/SemaCXX/dfp-types.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++2c -fexperimental-decimal-floating-point -fsyntax-only -verify %s
+
+using D32 = float __attribute__((mode(SD)));
+using D64 = float __attribute__((mode(DD)));
+using D128 = float __attribute__((mode(TD)));
+
+// Dependent type specifiers for the GNU mode attribute base type are ok, but
+// must be of a valid type when instantiated.
+template<typename T>
+T __attribute((mode(SD))) dtamsd; // expected-error {{type of machine mode does not match type of base type}}
+auto g1 = dtamsd<float>;
+auto g2 = dtamsd<double>;
+auto g3 = dtamsd<long double>;
+auto g4 = dtamsd<int>; // expected-note {{in instantiation of variable template specialization 'dtamsd' requested here}}

>From 3b2cb1f96976e6cbd712ff8062b24e326784b486 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom at honermann.net>
Date: Wed, 1 Nov 2023 16:58:47 -0400
Subject: [PATCH 4/5] [clang][DFP] Enable target dependent support for decimal
 floating-point extensions.

Support for decimal floating-point (DFP) extensions will, for most
targets, require run-time library support that, for many targets, is
not yet available. This change adds basic infrastructure support to
enable DFP support to be conditional on the target.

Some targets support more than one possible encoding of DFP values.
It is therefore necessary for a target to not just indicate that
DFP support is available, but also the encoding to be used. This
change recognizes the two known encodings that are used in practice
and ties DFP enablement to the selection of one of these modes.
The known encodings are:
  BID: Binary Integer Decimal
  DPD: Densely Packed Decimal
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +
 clang/include/clang/Basic/TargetInfo.h        | 27 ++++++
 clang/lib/Basic/TargetInfo.cpp                |  6 ++
 clang/lib/Basic/Targets/OSTargets.h           |  6 ++
 clang/lib/Frontend/InitPreprocessor.cpp       |  3 +-
 clang/lib/Sema/SemaDeclAttr.cpp               |  4 +
 clang/lib/Sema/SemaType.cpp                   |  4 +
 clang/test/Driver/dfp-enablement-target.c     | 82 +++++++++++++++++++
 8 files changed, 133 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/Driver/dfp-enablement-target.c

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d5c798b658e72..b79f4cc2c6e65 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10234,6 +10234,8 @@ def err_missing_type_specifier : Error<
   "a type specifier is required for all declarations">;
 def err_dfp_disabled : Error<
   "decimal floating-point extensions are not enabled">;
+def err_dfp_not_supported : Error<
+  "decimal floating-point extensions are not supported on the current target">;
 def err_objc_array_of_interfaces : Error<
   "array of interface %0 is invalid (probably should be an array of pointers)">;
 def ext_c99_array_usage : Extension<
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index f8734dcda10c7..f7c7ffe967129 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -220,6 +220,15 @@ enum OpenCLTypeKind : uint8_t {
   OCLTK_Sampler,
 };
 
+// ISO/IEC TS 18661-2, ISO/IEC TR 24733, and C23 decimal floating-point.
+// Multiple encoding forms for the storage of decimal floating-point values
+// have been defined for use on various platforms. This enumeration provides
+// an enumerator for each known encoding.
+enum class DecimalFloatMode : uint8_t {
+  BID,  // Binary Integer Decimal.
+  DPD,  // Densely Packed Decimal.
+};
+
 /// Exposes information about the current target.
 ///
 class TargetInfo : public TransferrableTargetInfo,
@@ -278,6 +287,10 @@ class TargetInfo : public TransferrableTargetInfo,
 
   std::optional<unsigned> MaxBitIntWidth;
 
+  // If disengaged, decimal floating-point extensions are not supported,
+  // otherwise, the decimal floating-point mode that is enabled.
+  std::optional<DecimalFloatMode> DecimalFloatEnablementAndMode;
+
   std::optional<llvm::Triple> DarwinTargetVariantTriple;
 
   // TargetInfo Constructor.  Default initializes all fields.
@@ -710,6 +723,20 @@ class TargetInfo : public TransferrableTargetInfo,
   /// Determine whether constrained floating point is supported on this target.
   virtual bool hasStrictFP() const { return HasStrictFP; }
 
+  /// Determine whether decimal floating-point extensions are enabled on this
+  /// target.
+  bool hasDecimalFloatingPoint() const {
+    return DecimalFloatEnablementAndMode.has_value();
+  }
+
+  /// Determine the encoding used for decimal floating-point values on this
+  /// target if decimal floating-point extensions are enabled.
+  DecimalFloatMode getDecimalFloatingPointMode() const {
+    assert(hasDecimalFloatingPoint() &&
+           "Decimal floating-point extensions are not enabled");
+    return DecimalFloatEnablementAndMode.value();
+  }
+
   /// Return the alignment that is the largest alignment ever used for any
   /// scalar/SIMD data type on the target machine you are compiling for
   /// (including types with an extended alignment requirement).
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 6b34c9e8d33eb..e62b215240ad3 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -524,6 +524,12 @@ void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
 
   if (Opts.FakeAddressSpaceMap)
     AddrSpaceMap = &FakeAddrSpaceMap;
+
+  // If decimal floating-point extensions are not enabled at the language
+  // level, reset the target dependent DFP mode configuration in order to
+  // avoid surprises.
+  if (!Opts.DecimalFloatingPoint)
+    DecimalFloatEnablementAndMode.reset();
 }
 
 bool TargetInfo::initFeatureMap(
diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h
index f2bd846e670d1..41abb01c42707 100644
--- a/clang/lib/Basic/Targets/OSTargets.h
+++ b/clang/lib/Basic/Targets/OSTargets.h
@@ -352,6 +352,12 @@ class LLVM_LIBRARY_VISIBILITY LinuxTargetInfo : public OSTargetInfo<Target> {
     case llvm::Triple::x86:
     case llvm::Triple::x86_64:
       this->HasFloat128 = true;
+      if (!Triple.isAndroid()) {
+        // Android NDK r23 and later no longer provide libgcc. DFP support
+        // for Android is therefore not enabled by default pending the
+        // availability of a different DFP run-time library.
+        this->DecimalFloatEnablementAndMode = DecimalFloatMode::BID;
+      }
       break;
     }
   }
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index ffa0eccce59b5..f0d0260625c17 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -501,7 +501,8 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
   // C23 decimal floating point extensions.
   // FIXME: Define to 202311L when support for C23 decimal floating point
   // FIXME: extensions is feature complete.
-  if (!LangOpts.CPlusPlus && LangOpts.DecimalFloatingPoint)
+  if (!LangOpts.CPlusPlus && LangOpts.DecimalFloatingPoint &&
+      TI.hasDecimalFloatingPoint())
     Builder.defineMacro("__STDC_IEC_60559_DFP__", "197001L");
 
   if (LangOpts.ObjC)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index cf9c51329577e..091b247f4794c 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4865,6 +4865,10 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
       Diag(AttrLoc, diag::err_dfp_disabled);
       return;
     }
+    if (!Context.getTargetInfo().hasDecimalFloatingPoint()) {
+      Diag(AttrLoc, diag::err_dfp_not_supported);
+      return;
+    }
   }
 
   if (ComplexMode) {
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index c3ab0d000f4d3..13c50b56972b7 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1592,6 +1592,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
       S.Diag(DS.getTypeSpecTypeLoc(), diag::err_dfp_disabled);
       Result = Context.IntTy;
       declarator.setInvalidType(true);
+    } else if (!S.Context.getTargetInfo().hasDecimalFloatingPoint()) {
+      S.Diag(DS.getTypeSpecTypeLoc(), diag::err_dfp_not_supported);
+      Result = Context.IntTy;
+      declarator.setInvalidType(true);
     } else {
       Result = TSTToDecimalFloatType(Context, DS.getTypeSpecType());
     }
diff --git a/clang/test/Driver/dfp-enablement-target.c b/clang/test/Driver/dfp-enablement-target.c
new file mode 100644
index 0000000000000..bd7e3e2a740a8
--- /dev/null
+++ b/clang/test/Driver/dfp-enablement-target.c
@@ -0,0 +1,82 @@
+// This test is intended to validate whether decimal floating-point (DFP)
+// extensions are supported and working for a given target and to ensure
+// that an appropriate diagnostic is issued when DFP features are used
+// otherwise.
+
+// FIXME: Remove all uses of -fexperimental-decimal-floating-point once -std=c23 implies DFP enablement.
+// RUN: %clang -target aarch64-unknown-freebsd       -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target aarch64-unknown-linux         -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target aarch64-unknown-linux-android -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target aarch64-unknown-windows-gnu   -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target aarch64-unknown-windows-msvc  -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target arm64-apple-darwin            -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target arm64-apple-ios               -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target arm64-apple-macos             -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target arm64-apple-tvos              -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target arm64-apple-watchos           -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target arm64-unknown-linux           -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target arm64-unknown-linux-android   -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target armv7-unknown-linux           -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target armv7-unknown-linux-android   -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target armv7-unknown-netbsd          -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target armv7-unknown-openbsd         -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target armv7-unknown-windows-gnu     -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target armv7-unknown-windows-msvc    -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target hexagon-unknown-linux         -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target i686-unknown-linux            -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify %s
+// RUN: %clang -target i686-unknown-linux-android    -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target i686-unknown-windows-gnu      -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target i686-unknown-windows-msvc     -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target loongarch32-unknown-linux     -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target loongarch64-unknown-linux     -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target m68k-unknown-linux            -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target mips-unknown-freebsd          -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target mips-unknown-linux            -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target mips64-unknown-freebsd        -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target mips64-unknown-linux          -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target powerpc64-ibm-aix             -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target powerpc64-unknown-linux       -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target powerpc-ibm-aix               -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target powerpc-unknown-linux         -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target riscv32-unknown-linux         -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target riscv64-unknown-freebsd       -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target riscv64-unknown-fuchsia       -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target riscv64-unknown-linux         -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target riscv64-unknown-openbsd       -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target s390x-ibm-linux               -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target s390x-ibm-zos                 -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target sparc-sun-solaris             -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target sparc-unknown-freebsd         -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target sparc-unknown-linux           -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target sparc-unknown-netbsd          -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target sparcv9-sun-solaris           -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target sparc64-unknown-freebsd       -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target sparc64-unknown-linux         -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target sparc64-unknown-netbsd        -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-apple-darwin           -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-apple-ios              -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-apple-macos            -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-apple-tvos             -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-apple-watchos          -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-unknown-freebsd        -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-unknown-fuchsia        -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-unknown-haiku          -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-unknown-linux          -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify %s
+// RUN: %clang -target x86_64-unknown-netbsd         -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-unknown-openbsd        -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-unknown-windows-gnu    -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+// RUN: %clang -target x86_64-unknown-windows-msvc   -std=c23 -fsyntax-only -fexperimental-decimal-floating-point -Xclang -verify=unsupported %s
+
+// expected-no-diagnostics
+
+_Decimal32 d32;   // unsupported-error {{decimal floating-point extensions are not supported on the current target}}
+_Decimal64 d64;   // unsupported-error {{decimal floating-point extensions are not supported on the current target}}
+_Decimal128 d128; // unsupported-error {{decimal floating-point extensions are not supported on the current target}}
+
+typedef float __attribute__((mode(SD))) D32;  // unsupported-error {{decimal floating-point extensions are not supported on the current target}}
+typedef float __attribute__((mode(DD))) D64;  // unsupported-error {{decimal floating-point extensions are not supported on the current target}}
+typedef float __attribute__((mode(TD))) D128; // unsupported-error {{decimal floating-point extensions are not supported on the current target}}
+
+float __attribute__((mode(SD))) famsd; // unsupported-error {{decimal floating-point extensions are not supported on the current target}}
+float __attribute__((mode(DD))) famdd; // unsupported-error {{decimal floating-point extensions are not supported on the current target}}
+float __attribute__((mode(TD))) famtd; // unsupported-error {{decimal floating-point extensions are not supported on the current target}}

>From 738500fa611d8c730e8b0a6dd4b3539018c99fd4 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 14 Nov 2023 14:31:40 -0800
Subject: [PATCH 5/5] [llvm] [DFP] Add support for decimal floating point IR
 types. (#33)

* Add support for DFP IR type.

* Fixed BitCodeFormat.rst format.

* Addressed review comments.

* Addressed review comments.

* Addressed review comments.

* Addressed review comments.

* Put all the Decimal* code together.

* Put all the Decimal* code together and removed unrelated
 changes.

* Fixed comment.

* Addressed review comments.

* Addressed review comments.

* Addressed review comments.

* Fixed reference.

* Fixed format.
---
 clang/lib/CodeGen/CodeGenTypes.cpp        |  7 +++--
 llvm/docs/BitCodeFormat.rst               | 24 +++++++++++++++
 llvm/docs/LangRef.rst                     |  9 ++++++
 llvm/include/llvm-c/Core.h                | 27 +++++++++++++++--
 llvm/include/llvm/Bitcode/LLVMBitCodes.h  |  4 +++
 llvm/include/llvm/IR/DataLayout.h         |  6 ++++
 llvm/include/llvm/IR/IRBuilder.h          | 15 ++++++++++
 llvm/include/llvm/IR/Type.h               | 36 ++++++++++++++++++++---
 llvm/lib/AsmParser/LLLexer.cpp            |  3 ++
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp |  9 ++++++
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp |  3 ++
 llvm/lib/IR/AsmWriter.cpp                 |  3 ++
 llvm/lib/IR/Core.cpp                      |  6 ++++
 llvm/lib/IR/LLVMContextImpl.cpp           |  4 ++-
 llvm/lib/IR/LLVMContextImpl.h             |  1 +
 llvm/lib/IR/Type.cpp                      | 22 ++++++++++++++
 llvm/test/Assembler/dfp.ll                | 16 ++++++++++
 17 files changed, 185 insertions(+), 10 deletions(-)
 create mode 100644 llvm/test/Assembler/dfp.ll

diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 9ec3d30968445..eb3f43ed149c4 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -419,10 +419,13 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
       break;
 
     case BuiltinType::DecimalFloat32:
+      ResultType = llvm::Type::getDecimal32Ty(getLLVMContext());
+      break;
     case BuiltinType::DecimalFloat64:
+      ResultType = llvm::Type::getDecimal64Ty(getLLVMContext());
+      break;
     case BuiltinType::DecimalFloat128:
-      llvm::report_fatal_error("LLVM type support for decimal floating point "
-                               "is not yet implemented");
+      ResultType = llvm::Type::getDecimal128Ty(getLLVMContext());
       break;
 
     case BuiltinType::NullPtr:
diff --git a/llvm/docs/BitCodeFormat.rst b/llvm/docs/BitCodeFormat.rst
index 70be73abef19d..2a91f64e2a6e0 100644
--- a/llvm/docs/BitCodeFormat.rst
+++ b/llvm/docs/BitCodeFormat.rst
@@ -1358,6 +1358,30 @@ The operand fields are
 
 * *int_params*: Numbers that correspond to the integer parameters.
 
+TYPE_CODE_DECIMAL32 Record
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``[DECIMAL32]``
+
+The ``DECIMAL32`` record (code 27) adds a ``decimal32`` (32-bit
+decimal floating point) type to the type table.
+
+TYPE_CODE_DECIMAL64 Record
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``[DECIMAL64]``
+
+The ``DECIMAL64`` record (code 28) adds a ``decimal64`` (64-bit
+decimal floating point) type to the type table.
+
+TYPE_CODE_DECIMAL128 Record
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``[DECIMAL128]``
+
+The ``DECIMAL128`` record (code 29) adds a ``decimal128`` (128-bit
+decimal floating point) type to the type table.
+
 .. _CONSTANTS_BLOCK:
 
 CONSTANTS_BLOCK Contents
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index f542e70bcfee8..e545f575f72b5 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -3672,6 +3672,15 @@ Floating-Point Types
    * - ``ppc_fp128``
      - 128-bit floating-point value (two 64-bits)
 
+   * - ``decimal32``
+     - 32-bit decimal floating-point value
+
+   * - ``decimal64``
+     - 64-bit decimal floating-point value
+
+   * - ``decimal128``
+     - 128-bit decimal floating-point value
+
 The binary format of half, float, double, and fp128 correspond to the
 IEEE-754-2008 specifications for binary16, binary32, binary64, and binary128
 respectively.
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 7ee46cac43042..f821d465b59a1 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -164,9 +164,12 @@ typedef enum {
   LLVMX86_MMXTypeKind,   /**< X86 MMX */
   LLVMTokenTypeKind,     /**< Tokens */
   LLVMScalableVectorTypeKind, /**< Scalable SIMD vector type */
-  LLVMBFloatTypeKind,    /**< 16 bit brain floating point type */
-  LLVMX86_AMXTypeKind,   /**< X86 AMX */
-  LLVMTargetExtTypeKind, /**< Target extension type */
+  LLVMBFloatTypeKind,         /**< 16 bit brain floating point type */
+  LLVMX86_AMXTypeKind,        /**< X86 AMX */
+  LLVMTargetExtTypeKind,      /**< Target extension type */
+  LLVMDecimal32TypeKind,      /**< 32 bit decimal floating point type */
+  LLVMDecimal64TypeKind,      /**< 64 bit decimal floating point type */
+  LLVMDecimal128TypeKind,     /**< 128 bit decimal floating point type */
 } LLVMTypeKind;
 
 typedef enum {
@@ -1290,6 +1293,21 @@ LLVMTypeRef LLVMFP128TypeInContext(LLVMContextRef C);
  */
 LLVMTypeRef LLVMPPCFP128TypeInContext(LLVMContextRef C);
 
+/**
+ * Obtain a 32-bit decimal floating point type from a context.
+ */
+LLVMTypeRef LLVMDecimal32TypeInContext(LLVMContextRef C);
+
+/**
+ * Obtain a 64-bit decimal floating point type from a context.
+ */
+LLVMTypeRef LLVMDecimal64TypeInContext(LLVMContextRef C);
+
+/**
+ * Obtain a 128-bit decimal floating point type from a context.
+ */
+LLVMTypeRef LLVMDecimal128TypeInContext(LLVMContextRef C);
+
 /**
  * Obtain a floating point type from the global context.
  *
@@ -1302,6 +1320,9 @@ LLVMTypeRef LLVMDoubleType(void);
 LLVMTypeRef LLVMX86FP80Type(void);
 LLVMTypeRef LLVMFP128Type(void);
 LLVMTypeRef LLVMPPCFP128Type(void);
+LLVMTypeRef LLVMDecimal32Type(void);
+LLVMTypeRef LLVMDecimal64Type(void);
+LLVMTypeRef LLVMDecimal128Type(void);
 
 /**
  * @}
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 52e76356a892e..d19978a08207b 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -177,6 +177,10 @@ enum TypeCodes {
   TYPE_CODE_OPAQUE_POINTER = 25, // OPAQUE_POINTER: [addrspace]
 
   TYPE_CODE_TARGET_TYPE = 26, // TARGET_TYPE
+
+  TYPE_CODE_DECIMAL32 = 27,  // 32-bit decimal floating point
+  TYPE_CODE_DECIMAL64 = 28,  // 64-bit decimal floating point
+  TYPE_CODE_DECIMAL128 = 29  // 128-bit decimal floating point
 };
 
 enum OperandBundleTagCode {
diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h
index b3633b67b9deb..c1fce09357ee3 100644
--- a/llvm/include/llvm/IR/DataLayout.h
+++ b/llvm/include/llvm/IR/DataLayout.h
@@ -715,6 +715,12 @@ inline TypeSize DataLayout::getTypeSizeInBits(Type *Ty) const {
     Type *LayoutTy = cast<TargetExtType>(Ty)->getLayoutType();
     return getTypeSizeInBits(LayoutTy);
   }
+  case Type::Decimal32TyID:
+    return TypeSize::Fixed(32);
+  case Type::Decimal64TyID:
+    return TypeSize::Fixed(64);
+  case Type::Decimal128TyID:
+    return TypeSize::Fixed(128);
   default:
     llvm_unreachable("DataLayout::getTypeSizeInBits(): Unsupported type");
   }
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index ef86eefdf33b8..ccae847c1cf8c 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -546,6 +546,21 @@ class IRBuilderBase {
     return Type::getDoubleTy(Context);
   }
 
+  /// Fetch the type representing a 32-bit decimal floating point value.
+  Type *getDecimal32Ty() {
+    return Type::getDecimal32Ty(Context);
+  }
+
+  /// Fetch the type representing a 64-bit decimal floating point value.
+  Type *getDecimal64Ty() {
+    return Type::getDecimal64Ty(Context);
+  }
+
+  /// Fetch the type representing a 128-bit decimal floating point value.
+  Type *getDecimal128Ty() {
+    return Type::getDecimal128Ty(Context);
+  }
+
   /// Fetch the type representing void.
   Type *getVoidTy() {
     return Type::getVoidTy(Context);
diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index c12e899d58fa8..9bebf361ddb63 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -67,6 +67,11 @@ class Type {
     X86_AMXTyID,   ///< AMX vectors (8192 bits, X86 specific)
     TokenTyID,     ///< Tokens
 
+    // Decimal floating-point types.
+    Decimal32TyID, ///< 32-bit decimal floating point type
+    Decimal64TyID, ///< 64-bit decimal floating point type
+    Decimal128TyID, ///< 128-bit decimal floating point type
+
     // Derived types... see DerivedTypes.h file.
     IntegerTyID,        ///< Arbitrary bit width integers
     FunctionTyID,       ///< Functions
@@ -165,6 +170,21 @@ class Type {
   /// Return true if this is powerpc long double.
   bool isPPC_FP128Ty() const { return getTypeID() == PPC_FP128TyID; }
 
+  /// Return true if this is 'decimal32'.
+  bool isDecimal32Ty() const { return getTypeID() == Decimal32TyID; }
+
+  /// Return true if this is 'decimal64'.
+  bool isDecimal64Ty() const { return getTypeID() == Decimal64TyID; }
+
+  /// Return true if this is 'decimal128'.
+  bool isDecimal128Ty() const { return getTypeID() == Decimal128TyID; }
+
+  /// Return true if this is a decimal floating point.
+  bool isDecimalFloatingPointTy() const {
+    return getTypeID() == Decimal32TyID || getTypeID() == Decimal64TyID ||
+           getTypeID() == Decimal128TyID;
+  }
+
   /// Return true if this is a well-behaved IEEE-like type, which has a IEEE
   /// compatible layout as defined by isIEEE(), and does not have unnormal
   /// values
@@ -184,7 +204,7 @@ class Type {
   /// Return true if this is one of the floating-point types
   bool isFloatingPointTy() const {
     return isIEEELikeFPTy() || getTypeID() == X86_FP80TyID ||
-           getTypeID() == PPC_FP128TyID;
+           getTypeID() == PPC_FP128TyID || isDecimalFloatingPointTy();
   }
 
   /// Returns true if this is a floating-point type that is an unevaluated sum
@@ -334,11 +354,16 @@ class Type {
   /// type.
   unsigned getScalarSizeInBits() const LLVM_READONLY;
 
-  /// Return the width of the mantissa of this type. This is only valid on
-  /// floating-point types. If the FP type does not have a stable mantissa (e.g.
-  /// ppc long double), this method returns -1.
+  /// Return the width of the mantissa of this type, in bits. This is only valid
+  /// on floating-point types. If the FP type does not have a stable mantissa
+  /// (e.g. ppc long double), this method returns -1.
   int getFPMantissaWidth() const;
 
+  /// Return the precision in digits of a decimal floating-point type
+  /// per the "Decimal interchange format parameters" table of
+  /// C23 annex H.2.1, "Interchange floating types".
+  int getDFPPrecisionInDigits() const;
+
   /// Return whether the type is IEEE compatible, as defined by the eponymous
   /// method in APFloat.
   bool isIEEE() const;
@@ -463,6 +488,9 @@ class Type {
   static IntegerType *getInt32Ty(LLVMContext &C);
   static IntegerType *getInt64Ty(LLVMContext &C);
   static IntegerType *getInt128Ty(LLVMContext &C);
+  static Type *getDecimal32Ty(LLVMContext &C);
+  static Type *getDecimal64Ty(LLVMContext &C);
+  static Type *getDecimal128Ty(LLVMContext &C);
   template <typename ScalarTy> static Type *getScalarTy(LLVMContext &C) {
     int noOfBits = sizeof(ScalarTy) * CHAR_BIT;
     if (std::is_integral<ScalarTy>::value) {
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 466bdebc001f5..271fdbf860d74 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -826,6 +826,9 @@ lltok::Kind LLLexer::LexIdentifier() {
   TYPEKEYWORD("x86_amx",   Type::getX86_AMXTy(Context));
   TYPEKEYWORD("token",     Type::getTokenTy(Context));
   TYPEKEYWORD("ptr",       PointerType::getUnqual(Context));
+  TYPEKEYWORD("decimal32", Type::getDecimal32Ty(Context));
+  TYPEKEYWORD("decimal64", Type::getDecimal64Ty(Context));
+  TYPEKEYWORD("decimal128", Type::getDecimal128Ty(Context));
 
 #undef TYPEKEYWORD
 
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 1d1ec988a93d8..d6ccf83b48477 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2508,6 +2508,15 @@ Error BitcodeReader::parseTypeTableBody() {
       TypeName.clear();
       break;
     }
+    case bitc::TYPE_CODE_DECIMAL32: // 32-bit DFP
+      ResultTy = Type::getDecimal32Ty(Context);
+      break;
+    case bitc::TYPE_CODE_DECIMAL64: // 64-bit DFP
+      ResultTy = Type::getDecimal64Ty(Context);
+      break;
+    case bitc::TYPE_CODE_DECIMAL128: // 128-bit DFP
+      ResultTy = Type::getDecimal128Ty(Context);
+      break;
     case bitc::TYPE_CODE_ARRAY:     // ARRAY: [numelts, eltty]
       if (Record.size() < 2)
         return error("Invalid array type record");
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index f53fbd7366776..73d74a4729f4d 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -976,6 +976,9 @@ void ModuleBitcodeWriter::writeTypeTable() {
     case Type::X86_FP80TyID:  Code = bitc::TYPE_CODE_X86_FP80;  break;
     case Type::FP128TyID:     Code = bitc::TYPE_CODE_FP128;     break;
     case Type::PPC_FP128TyID: Code = bitc::TYPE_CODE_PPC_FP128; break;
+    case Type::Decimal32TyID: Code = bitc::TYPE_CODE_DECIMAL32; break;
+    case Type::Decimal64TyID: Code = bitc::TYPE_CODE_DECIMAL64; break;
+    case Type::Decimal128TyID: Code = bitc::TYPE_CODE_DECIMAL128; break;
     case Type::LabelTyID:     Code = bitc::TYPE_CODE_LABEL;     break;
     case Type::MetadataTyID:  Code = bitc::TYPE_CODE_METADATA;  break;
     case Type::X86_MMXTyID:   Code = bitc::TYPE_CODE_X86_MMX;   break;
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index e190d82127908..30bc27f5a3ec1 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -561,6 +561,9 @@ void TypePrinting::print(Type *Ty, raw_ostream &OS) {
   case Type::IntegerTyID:
     OS << 'i' << cast<IntegerType>(Ty)->getBitWidth();
     return;
+  case Type::Decimal32TyID:  OS << "decimal32"; return;
+  case Type::Decimal64TyID:  OS << "decimal64"; return;
+  case Type::Decimal128TyID: OS << "decimal128"; return;
 
   case Type::FunctionTyID: {
     FunctionType *FTy = cast<FunctionType>(Ty);
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 17093fa0ac4ee..0de684136bd21 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -563,6 +563,12 @@ LLVMTypeKind LLVMGetTypeKind(LLVMTypeRef Ty) {
     return LLVMFP128TypeKind;
   case Type::PPC_FP128TyID:
     return LLVMPPC_FP128TypeKind;
+  case Type::Decimal32TyID:
+    return LLVMDecimal32TypeKind;
+  case Type::Decimal64TyID:
+    return LLVMDecimal64TypeKind;
+  case Type::Decimal128TyID:
+    return LLVMDecimal128TypeKind;
   case Type::LabelTyID:
     return LLVMLabelTypeKind;
   case Type::MetadataTyID:
diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp
index 2076eeed94176..20d2766eae22d 100644
--- a/llvm/lib/IR/LLVMContextImpl.cpp
+++ b/llvm/lib/IR/LLVMContextImpl.cpp
@@ -42,7 +42,9 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
       X86_FP80Ty(C, Type::X86_FP80TyID), FP128Ty(C, Type::FP128TyID),
       PPC_FP128Ty(C, Type::PPC_FP128TyID), X86_MMXTy(C, Type::X86_MMXTyID),
       X86_AMXTy(C, Type::X86_AMXTyID), Int1Ty(C, 1), Int8Ty(C, 8),
-      Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), Int128Ty(C, 128) {}
+      Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), Int128Ty(C, 128),
+      Decimal32Ty(C, Type::Decimal32TyID), Decimal64Ty(C, Type::Decimal64TyID),
+      Decimal128Ty(C, Type::Decimal128TyID) {}
 
 LLVMContextImpl::~LLVMContextImpl() {
   // NOTE: We need to delete the contents of OwnedModules, but Module's dtor
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 4cc3f8da6b75b..0530cec970071 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -1524,6 +1524,7 @@ class LLVMContextImpl {
       TokenTy;
   Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_MMXTy, X86_AMXTy;
   IntegerType Int1Ty, Int8Ty, Int16Ty, Int32Ty, Int64Ty, Int128Ty;
+  Type Decimal32Ty, Decimal64Ty, Decimal128Ty;
 
   std::unique_ptr<ConstantTokenNone> TheNoneToken;
 
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 97febcd99b411..5cf2ec8faf28f 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -48,6 +48,9 @@ Type *Type::getPrimitiveType(LLVMContext &C, TypeID IDNumber) {
   case X86_MMXTyID   : return getX86_MMXTy(C);
   case X86_AMXTyID   : return getX86_AMXTy(C);
   case TokenTyID     : return getTokenTy(C);
+  case Decimal32TyID :  return getDecimal32Ty(C);
+  case Decimal64TyID :  return getDecimal64Ty(C);
+  case Decimal128TyID: return getDecimal128Ty(C);
   default:
     return nullptr;
   }
@@ -179,6 +182,9 @@ TypeSize Type::getPrimitiveSizeInBits() const {
   case Type::X86_FP80TyID: return TypeSize::Fixed(80);
   case Type::FP128TyID: return TypeSize::Fixed(128);
   case Type::PPC_FP128TyID: return TypeSize::Fixed(128);
+  case Decimal32TyID: return TypeSize::Fixed(32);
+  case Decimal64TyID: return TypeSize::Fixed(64);
+  case Decimal128TyID: return TypeSize::Fixed(128);
   case Type::X86_MMXTyID: return TypeSize::Fixed(64);
   case Type::X86_AMXTyID: return TypeSize::Fixed(8192);
   case Type::IntegerTyID:
@@ -214,6 +220,18 @@ int Type::getFPMantissaWidth() const {
   return -1;
 }
 
+int Type::getDFPPrecisionInDigits() const {
+  if (auto *VTy = dyn_cast<VectorType>(this))
+    return VTy->getElementType()->getDFPPrecisionInDigits();
+  assert(isDecimalFloatingPointTy() && "Not a decimal floating point type!");
+  // Precision values per the "Decimal interchange format parameters" table of
+  /// C23 annex H.2.1, "Interchange floating types".
+  if (getTypeID() == Decimal32TyID) return 7;
+  if (getTypeID() == Decimal64TyID) return 16;
+  if (getTypeID() == Decimal128TyID) return 34;
+  report_fatal_error("unknown decimal floating point type");
+}
+
 bool Type::isSizedDerivedType(SmallPtrSetImpl<Type*> *Visited) const {
   if (auto *ATy = dyn_cast<ArrayType>(this))
     return ATy->getElementType()->isSized(Visited);
@@ -245,6 +263,10 @@ Type *Type::getPPC_FP128Ty(LLVMContext &C) { return &C.pImpl->PPC_FP128Ty; }
 Type *Type::getX86_MMXTy(LLVMContext &C) { return &C.pImpl->X86_MMXTy; }
 Type *Type::getX86_AMXTy(LLVMContext &C) { return &C.pImpl->X86_AMXTy; }
 
+Type *Type::getDecimal32Ty(LLVMContext &C) { return &C.pImpl->Decimal32Ty; }
+Type *Type::getDecimal64Ty(LLVMContext &C) { return &C.pImpl->Decimal64Ty; }
+Type *Type::getDecimal128Ty(LLVMContext &C) { return &C.pImpl->Decimal128Ty; }
+
 IntegerType *Type::getInt1Ty(LLVMContext &C) { return &C.pImpl->Int1Ty; }
 IntegerType *Type::getInt8Ty(LLVMContext &C) { return &C.pImpl->Int8Ty; }
 IntegerType *Type::getInt16Ty(LLVMContext &C) { return &C.pImpl->Int16Ty; }
diff --git a/llvm/test/Assembler/dfp.ll b/llvm/test/Assembler/dfp.ll
new file mode 100644
index 0000000000000..8f93eef6836cb
--- /dev/null
+++ b/llvm/test/Assembler/dfp.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s --check-prefix=ASSEM-DISASS
+
+define decimal32 @check_decimal32(decimal32 %A) {
+; ASSEM-DISASS: ret decimal32 %A
+    ret decimal32 %A
+}
+
+define decimal64 @check_decimal64(decimal64 %A) {
+; ASSEM-DISASS: ret decimal64 %A
+    ret decimal64 %A
+}
+
+define decimal128 @check_decimal128(decimal128 %A) {
+; ASSEM-DISASS: ret decimal128 %A
+  ret decimal128 %A
+}



More information about the cfe-commits mailing list