[clang] Dfpir types (PR #70127)

Zahira Ammarguellat via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 24 14:32:27 PDT 2023


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

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/4] [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 4ee32c76a95d8e3..f862456797b5f92 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 c04f6f6f1271916..3a0f78fb6a33fa9 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 61be52149341f01..ddf166c971fec95 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 72e8df8c793a7b6..fdbeaddd9ab9c3d 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 9e115f2a5cce3f9..e83c8cafcac36f1 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 4b1d9e86797b778..1a411232cab9dba 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 fea06b97259fe31..b048ef1c2c4421c 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 53963d2a91752a8..7641f44d7225462 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 79175c79de96bf8..0e68e6acf6291e3 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 86dee540e9e2995..adcae62f81d1638 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 f0b9d0ecaf23461..d7d6bd94c387be1 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 c08ebfb7f142b35..91de51add303e4a 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 e12b9b50f6e7224..8556488ab67dc24 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 6cd5d618a4acaa5..5cd7e259db90de7 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 36e29285141b593..283d7bb4645b9b9 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 30021794a0bb3d3..9ec3d309684450a 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 385dcf21f724e9c..797103257ed89e5 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 f778a6208d5122d..4ab9370e8a80458 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 ffd29446b4f2edd..fa515dd3bc93579 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 72e582107480976..17abf2188af9a95 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 0952244d037a77c..9d6a018177b0981 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 e0a6ba4f0691b95..4ce8d5ffffb76ee 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 f0c8ecfcb6264fb..e9d97d550282347 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/4] [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 0ac4df8edb242f6..d5c798b658e72f4 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 e18b5b80a34e718..2902c4d891c5a72 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 fdbeaddd9ab9c3d..12f80e38ded9bbb 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 553c7928c4f949e..8a510295d344109 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 40e60585a8b8d6e..d98574def75de76 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 e5db8a654e6707d..ffa0eccce59b5ee 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 fa515dd3bc93579..c3ab0d000f4d3c6 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 000000000000000..fe566e6cef848d9
--- /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 000000000000000..86bb5ce945ca110
--- /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 4ce8d5ffffb76ee..9f7e1f48d5631fc 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/4] [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 46dbadd8b878bf0..3fcec7b594abc9c 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 ddf166c971fec95..f8734dcda10c72e 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 1a411232cab9dba..0aef78b685460da 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 91de51add303e4a..26d813b160bc3d7 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 5cd7e259db90de7..6b34c9e8d33eb1c 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 fad70223362eddd..97f175f770ca304 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 cc98713241395ec..cf9c51329577efd 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 fe566e6cef848d9..05406d653a69f54 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 86bb5ce945ca110..330fb898f9414e2 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 000000000000000..9a26aefab20f6d5
--- /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 9b859250d9f7983304d941be735178134f65964c Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Fri, 20 Oct 2023 05:54:53 -0700
Subject: [PATCH 4/4] Add support for DFP IR type.

---
 llvm/docs/BitCodeFormat.rst               | 24 +++++++++++++++++++++++
 llvm/docs/LangRef.rst                     |  9 +++++++++
 llvm/include/llvm-c/Core.h                | 21 ++++++++++++++++++++
 llvm/include/llvm/Bitcode/LLVMBitCodes.h  |  4 ++++
 llvm/include/llvm/IR/DataLayout.h         |  3 +++
 llvm/include/llvm/IR/IRBuilder.h          | 15 ++++++++++++++
 llvm/include/llvm/IR/Type.h               | 18 +++++++++++++++++
 llvm/lib/AsmParser/LLLexer.cpp            |  6 ++++++
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp |  9 +++++++++
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp |  9 +++++++++
 llvm/lib/IR/AsmWriter.cpp                 |  9 +++++++++
 llvm/lib/IR/Core.cpp                      |  6 ++++++
 llvm/lib/IR/LLVMContextImpl.cpp           |  6 ++++--
 llvm/lib/IR/LLVMContextImpl.h             |  5 +++--
 llvm/lib/IR/Type.cpp                      | 18 +++++++++++++++++
 llvm/test/Assembler/dfp.ll                | 16 +++++++++++++++
 16 files changed, 174 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/Assembler/dfp.ll

diff --git a/llvm/docs/BitCodeFormat.rst b/llvm/docs/BitCodeFormat.rst
index 70be73abef19d6d..d83f2927a8fe001 100644
--- a/llvm/docs/BitCodeFormat.rst
+++ b/llvm/docs/BitCodeFormat.rst
@@ -1360,6 +1360,30 @@ The operand fields are
 
 .. _CONSTANTS_BLOCK:
 
+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 Contents
 ------------------------
 
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index f542e70bcfee810..37c2de43ab36de3 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -3660,9 +3660,15 @@ Floating-Point Types
    * - ``float``
      - 32-bit floating-point value
 
+   * - ``decimal32``
+     - 32-bit decimal floating-point value
+
    * - ``double``
      - 64-bit floating-point value
 
+   * - ``decimal64``
+     - 64-bit decimal floating-point value
+
    * - ``fp128``
      - 128-bit floating-point value (113-bit significand)
 
@@ -3672,6 +3678,9 @@ Floating-Point Types
    * - ``ppc_fp128``
      - 128-bit floating-point value (two 64-bits)
 
+   * - ``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 7ee46cac43042a1..101ca5588b4da40 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -149,10 +149,13 @@ typedef enum {
   LLVMVoidTypeKind,      /**< type with no size */
   LLVMHalfTypeKind,      /**< 16 bit floating point type */
   LLVMFloatTypeKind,     /**< 32 bit floating point type */
+  LLVMDecimal32TypeKind, /**< 32 bit decimal floating point type */
   LLVMDoubleTypeKind,    /**< 64 bit floating point type */
+  LLVMDecimal64TypeKind, /**< 64 bit decimal floating point type */
   LLVMX86_FP80TypeKind,  /**< 80 bit floating point type (X87) */
   LLVMFP128TypeKind,     /**< 128 bit floating point type (112-bit mantissa)*/
   LLVMPPC_FP128TypeKind, /**< 128 bit floating point type (two 64-bits) */
+  LLVMDecimal128TypeKind,/**< 128 bit decimal floating point type */
   LLVMLabelTypeKind,     /**< Labels */
   LLVMIntegerTypeKind,   /**< Arbitrary bit width integers */
   LLVMFunctionTypeKind,  /**< Functions */
@@ -1269,11 +1272,21 @@ LLVMTypeRef LLVMBFloatTypeInContext(LLVMContextRef C);
  */
 LLVMTypeRef LLVMFloatTypeInContext(LLVMContextRef C);
 
+/**
+ * Obtain a 32-bit decimal floating point type from a context.
+ */
+LLVMTypeRef LLVMDecimal32TypeInContext(LLVMContextRef C);
+
 /**
  * Obtain a 64-bit floating point type from a context.
  */
 LLVMTypeRef LLVMDoubleTypeInContext(LLVMContextRef C);
 
+/**
+ * Obtain a 64-bit decimal floating point type from a context.
+ */
+LLVMTypeRef LLVMDecimal64TypeInContext(LLVMContextRef C);
+
 /**
  * Obtain a 80-bit floating point type (X87) from a context.
  */
@@ -1290,6 +1303,11 @@ LLVMTypeRef LLVMFP128TypeInContext(LLVMContextRef C);
  */
 LLVMTypeRef LLVMPPCFP128TypeInContext(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.
  *
@@ -1298,10 +1316,13 @@ LLVMTypeRef LLVMPPCFP128TypeInContext(LLVMContextRef C);
 LLVMTypeRef LLVMHalfType(void);
 LLVMTypeRef LLVMBFloatType(void);
 LLVMTypeRef LLVMFloatType(void);
+LLVMTypeRef LLVMDecimal32Type(void);
 LLVMTypeRef LLVMDoubleType(void);
+LLVMTypeRef LLVMDecimal64Type(void);
 LLVMTypeRef LLVMX86FP80Type(void);
 LLVMTypeRef LLVMFP128Type(void);
 LLVMTypeRef LLVMPPCFP128Type(void);
+LLVMTypeRef LLVMDecimal128Type(void);
 
 /**
  * @}
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 52e76356a892e45..d19978a08207bd6 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 b3633b67b9debda..6a95519f18e0297 100644
--- a/llvm/include/llvm/IR/DataLayout.h
+++ b/llvm/include/llvm/IR/DataLayout.h
@@ -690,12 +690,15 @@ inline TypeSize DataLayout::getTypeSizeInBits(Type *Ty) const {
   case Type::BFloatTyID:
     return TypeSize::Fixed(16);
   case Type::FloatTyID:
+  case Type::Decimal32TyID:
     return TypeSize::Fixed(32);
   case Type::DoubleTyID:
   case Type::X86_MMXTyID:
+  case Type::Decimal64TyID:
     return TypeSize::Fixed(64);
   case Type::PPC_FP128TyID:
   case Type::FP128TyID:
+  case Type::Decimal128TyID:
     return TypeSize::Fixed(128);
   case Type::X86_AMXTyID:
     return TypeSize::Fixed(8192);
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index ef86eefdf33b834..5e27acedd0540ef 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -541,11 +541,26 @@ class IRBuilderBase {
     return Type::getFloatTy(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 floating point value.
   Type *getDoubleTy() {
     return Type::getDoubleTy(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 c12e899d58fa834..4341f50799dabc9 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -56,10 +56,13 @@ class Type {
     HalfTyID = 0,  ///< 16-bit floating point type
     BFloatTyID,    ///< 16-bit floating point type (7-bit significand)
     FloatTyID,     ///< 32-bit floating point type
+    Decimal32TyID, ///< 32-bit decimal floating point type
     DoubleTyID,    ///< 64-bit floating point type
+    Decimal64TyID, ///< 64-bit decimal floating point type
     X86_FP80TyID,  ///< 80-bit floating point type (X87)
     FP128TyID,     ///< 128-bit floating point type (112-bit significand)
     PPC_FP128TyID, ///< 128-bit floating point type (two 64-bits, PowerPC)
+    Decimal128TyID,///< 128-bit decimal floating point type
     VoidTyID,      ///< type with no size
     LabelTyID,     ///< Labels
     MetadataTyID,  ///< Metadata
@@ -165,6 +168,15 @@ 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 well-behaved IEEE-like type, which has a IEEE
   /// compatible layout as defined by isIEEE(), and does not have unnormal
   /// values
@@ -175,6 +187,9 @@ class Type {
     case HalfTyID:
     case BFloatTyID:
     case FP128TyID:
+    case Decimal32TyID:
+    case Decimal64TyID:
+    case Decimal128TyID:
       return true;
     default:
       return false;
@@ -448,11 +463,14 @@ class Type {
   static Type *getHalfTy(LLVMContext &C);
   static Type *getBFloatTy(LLVMContext &C);
   static Type *getFloatTy(LLVMContext &C);
+  static Type *getDecimal32Ty(LLVMContext &C);
   static Type *getDoubleTy(LLVMContext &C);
+  static Type *getDecimal64Ty(LLVMContext &C);
   static Type *getMetadataTy(LLVMContext &C);
   static Type *getX86_FP80Ty(LLVMContext &C);
   static Type *getFP128Ty(LLVMContext &C);
   static Type *getPPC_FP128Ty(LLVMContext &C);
+  static Type *getDecimal128Ty(LLVMContext &C);
   static Type *getX86_MMXTy(LLVMContext &C);
   static Type *getX86_AMXTy(LLVMContext &C);
   static Type *getTokenTy(LLVMContext &C);
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 466bdebc001f589..6756bdd9b21a8bc 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -816,10 +816,13 @@ lltok::Kind LLLexer::LexIdentifier() {
   TYPEKEYWORD("half",      Type::getHalfTy(Context));
   TYPEKEYWORD("bfloat",    Type::getBFloatTy(Context));
   TYPEKEYWORD("float",     Type::getFloatTy(Context));
+  TYPEKEYWORD("decimal32", Type::getDecimal32Ty(Context));
   TYPEKEYWORD("double",    Type::getDoubleTy(Context));
+  TYPEKEYWORD("decimal64", Type::getDecimal64Ty(Context));
   TYPEKEYWORD("x86_fp80",  Type::getX86_FP80Ty(Context));
   TYPEKEYWORD("fp128",     Type::getFP128Ty(Context));
   TYPEKEYWORD("ppc_fp128", Type::getPPC_FP128Ty(Context));
+  TYPEKEYWORD("decimal128", Type::getDecimal128Ty(Context));
   TYPEKEYWORD("label",     Type::getLabelTy(Context));
   TYPEKEYWORD("metadata",  Type::getMetadataTy(Context));
   TYPEKEYWORD("x86_mmx",   Type::getX86_MMXTy(Context));
@@ -984,6 +987,9 @@ lltok::Kind LLLexer::LexIdentifier() {
 ///    HexPPC128Constant 0xM[0-9A-Fa-f]+
 ///    HexHalfConstant   0xH[0-9A-Fa-f]+
 ///    HexBFloatConstant 0xR[0-9A-Fa-f]+
+///    HexDecimal32Constant 0xR[0-9A-Fa-f]+
+///    HexDecimal64Constant 0xR[0-9A-Fa-f]+
+///    HexDecimal128Constant 0xR[0-9A-Fa-f]+
 lltok::Kind LLLexer::Lex0x() {
   CurPtr = TokStart + 2;
 
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 1d1ec988a93d847..d96e9d2d6aedaa3 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2306,9 +2306,15 @@ Error BitcodeReader::parseTypeTableBody() {
     case bitc::TYPE_CODE_FLOAT:     // FLOAT
       ResultTy = Type::getFloatTy(Context);
       break;
+    case bitc::TYPE_CODE_DECIMAL32: // 32-bit DFP
+      ResultTy = Type::getDecimal32Ty(Context);
+      break;
     case bitc::TYPE_CODE_DOUBLE:    // DOUBLE
       ResultTy = Type::getDoubleTy(Context);
       break;
+    case bitc::TYPE_CODE_DECIMAL64: // 64-bit DFP
+      ResultTy = Type::getDecimal64Ty(Context);
+      break;
     case bitc::TYPE_CODE_X86_FP80:  // X86_FP80
       ResultTy = Type::getX86_FP80Ty(Context);
       break;
@@ -2318,6 +2324,9 @@ Error BitcodeReader::parseTypeTableBody() {
     case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128
       ResultTy = Type::getPPC_FP128Ty(Context);
       break;
+    case bitc::TYPE_CODE_DECIMAL128: // 128-bit DFP
+      ResultTy = Type::getDecimal128Ty(Context);
+      break;
     case bitc::TYPE_CODE_LABEL:     // LABEL
       ResultTy = Type::getLabelTy(Context);
       break;
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index f53fbd73667762c..97b790b08008aea 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -972,10 +972,19 @@ void ModuleBitcodeWriter::writeTypeTable() {
     case Type::HalfTyID:      Code = bitc::TYPE_CODE_HALF;      break;
     case Type::BFloatTyID:    Code = bitc::TYPE_CODE_BFLOAT;    break;
     case Type::FloatTyID:     Code = bitc::TYPE_CODE_FLOAT;     break;
+    case Type::Decimal32TyID:
+      Code = bitc::TYPE_CODE_DECIMAL32;
+      break;
     case Type::DoubleTyID:    Code = bitc::TYPE_CODE_DOUBLE;    break;
+    case Type::Decimal64TyID:
+      Code = bitc::TYPE_CODE_DECIMAL64;
+      break;
     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::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 e190d82127908db..a9a705e8cc8e8e0 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -549,10 +549,19 @@ void TypePrinting::print(Type *Ty, raw_ostream &OS) {
   case Type::HalfTyID:      OS << "half"; return;
   case Type::BFloatTyID:    OS << "bfloat"; return;
   case Type::FloatTyID:     OS << "float"; return;
+  case Type::Decimal32TyID:
+    OS << "decimal32";
+    return;
   case Type::DoubleTyID:    OS << "double"; return;
+  case Type::Decimal64TyID:
+    OS << "decimal64";
+    return;
   case Type::X86_FP80TyID:  OS << "x86_fp80"; return;
   case Type::FP128TyID:     OS << "fp128"; return;
   case Type::PPC_FP128TyID: OS << "ppc_fp128"; return;
+  case Type::Decimal128TyID:
+    OS << "decimal128";
+    return;
   case Type::LabelTyID:     OS << "label"; return;
   case Type::MetadataTyID:  OS << "metadata"; return;
   case Type::X86_MMXTyID:   OS << "x86_mmx"; return;
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 17093fa0ac4ee1e..3108533bafd0fde 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -555,14 +555,20 @@ LLVMTypeKind LLVMGetTypeKind(LLVMTypeRef Ty) {
     return LLVMBFloatTypeKind;
   case Type::FloatTyID:
     return LLVMFloatTypeKind;
+  case Type::Decimal32TyID:
+    return LLVMDecimal32TypeKind;
   case Type::DoubleTyID:
     return LLVMDoubleTypeKind;
+  case Type::Decimal64TyID:
+    return LLVMDecimal64TypeKind;
   case Type::X86_FP80TyID:
     return LLVMX86_FP80TypeKind;
   case Type::FP128TyID:
     return LLVMFP128TypeKind;
   case Type::PPC_FP128TyID:
     return LLVMPPC_FP128TypeKind;
+  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 2076eeed9417691..746f08020fc06cb 100644
--- a/llvm/lib/IR/LLVMContextImpl.cpp
+++ b/llvm/lib/IR/LLVMContextImpl.cpp
@@ -37,10 +37,12 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
     : DiagHandler(std::make_unique<DiagnosticHandler>()),
       VoidTy(C, Type::VoidTyID), LabelTy(C, Type::LabelTyID),
       HalfTy(C, Type::HalfTyID), BFloatTy(C, Type::BFloatTyID),
-      FloatTy(C, Type::FloatTyID), DoubleTy(C, Type::DoubleTyID),
+      FloatTy(C, Type::FloatTyID), Decimal32Ty(C, Type::Decimal32TyID),
+      DoubleTy(C, Type::DoubleTyID), Decimal64Ty(C, Type::Decimal64TyID),
       MetadataTy(C, Type::MetadataTyID), TokenTy(C, Type::TokenTyID),
       X86_FP80Ty(C, Type::X86_FP80TyID), FP128Ty(C, Type::FP128TyID),
-      PPC_FP128Ty(C, Type::PPC_FP128TyID), X86_MMXTy(C, Type::X86_MMXTyID),
+      PPC_FP128Ty(C, Type::PPC_FP128TyID),
+      Decimal128Ty(C, Type::Decimal128TyID), 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) {}
 
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 4cc3f8da6b75b5d..306b266f4397fb9 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -1520,9 +1520,10 @@ class LLVMContextImpl {
   ConstantInt *TheFalseVal = nullptr;
 
   // Basic type instances.
-  Type VoidTy, LabelTy, HalfTy, BFloatTy, FloatTy, DoubleTy, MetadataTy,
+  Type VoidTy, LabelTy, HalfTy, BFloatTy, FloatTy, Decimal32Ty, DoubleTy,
+      Decimal64Ty, MetadataTy,
       TokenTy;
-  Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_MMXTy, X86_AMXTy;
+  Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, Decimal128Ty, X86_MMXTy, X86_AMXTy;
   IntegerType Int1Ty, Int8Ty, Int16Ty, Int32Ty, Int64Ty, Int128Ty;
 
   std::unique_ptr<ConstantTokenNone> TheNoneToken;
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 97febcd99b4114f..0e0e501409817d0 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -39,10 +39,16 @@ Type *Type::getPrimitiveType(LLVMContext &C, TypeID IDNumber) {
   case HalfTyID      : return getHalfTy(C);
   case BFloatTyID    : return getBFloatTy(C);
   case FloatTyID     : return getFloatTy(C);
+  case Decimal32TyID:
+    return getDecimal32Ty(C);
   case DoubleTyID    : return getDoubleTy(C);
+  case Decimal64TyID:
+    return getDecimal64Ty(C);
   case X86_FP80TyID  : return getX86_FP80Ty(C);
   case FP128TyID     : return getFP128Ty(C);
   case PPC_FP128TyID : return getPPC_FP128Ty(C);
+  case Decimal128TyID:
+    return getDecimal128Ty(C);
   case LabelTyID     : return getLabelTy(C);
   case MetadataTyID  : return getMetadataTy(C);
   case X86_MMXTyID   : return getX86_MMXTy(C);
@@ -175,10 +181,13 @@ TypeSize Type::getPrimitiveSizeInBits() const {
   case Type::HalfTyID: return TypeSize::Fixed(16);
   case Type::BFloatTyID: return TypeSize::Fixed(16);
   case Type::FloatTyID: return TypeSize::Fixed(32);
+  case Decimal32TyID: return TypeSize::Fixed(32);
   case Type::DoubleTyID: return TypeSize::Fixed(64);
+  case Decimal64TyID: return TypeSize::Fixed(64);
   case Type::X86_FP80TyID: return TypeSize::Fixed(80);
   case Type::FP128TyID: return TypeSize::Fixed(128);
   case Type::PPC_FP128TyID: return TypeSize::Fixed(128);
+  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:
@@ -207,9 +216,15 @@ int Type::getFPMantissaWidth() const {
   if (getTypeID() == HalfTyID) return 11;
   if (getTypeID() == BFloatTyID) return 8;
   if (getTypeID() == FloatTyID) return 24;
+  // TODO - Does this depend on the encoding format used (BID or DPD)?
+  if (getTypeID() == Decimal32TyID) return 20;
   if (getTypeID() == DoubleTyID) return 53;
+  // TODO - Does this depend on the encoding format used (BID or DPD)?
+  if (getTypeID() == Decimal64TyID) return 50;
   if (getTypeID() == X86_FP80TyID) return 64;
   if (getTypeID() == FP128TyID) return 113;
+  // TODO - Does this depend on the encoding format used (BID or DPD)?
+  if (getTypeID() == Decimal128TyID) return 110;
   assert(getTypeID() == PPC_FP128TyID && "unknown fp type");
   return -1;
 }
@@ -236,12 +251,15 @@ Type *Type::getLabelTy(LLVMContext &C) { return &C.pImpl->LabelTy; }
 Type *Type::getHalfTy(LLVMContext &C) { return &C.pImpl->HalfTy; }
 Type *Type::getBFloatTy(LLVMContext &C) { return &C.pImpl->BFloatTy; }
 Type *Type::getFloatTy(LLVMContext &C) { return &C.pImpl->FloatTy; }
+Type *Type::getDecimal32Ty(LLVMContext &C) { return &C.pImpl->Decimal32Ty; }
 Type *Type::getDoubleTy(LLVMContext &C) { return &C.pImpl->DoubleTy; }
+Type *Type::getDecimal64Ty(LLVMContext &C) { return &C.pImpl->Decimal64Ty; }
 Type *Type::getMetadataTy(LLVMContext &C) { return &C.pImpl->MetadataTy; }
 Type *Type::getTokenTy(LLVMContext &C) { return &C.pImpl->TokenTy; }
 Type *Type::getX86_FP80Ty(LLVMContext &C) { return &C.pImpl->X86_FP80Ty; }
 Type *Type::getFP128Ty(LLVMContext &C) { return &C.pImpl->FP128Ty; }
 Type *Type::getPPC_FP128Ty(LLVMContext &C) { return &C.pImpl->PPC_FP128Ty; }
+Type *Type::getDecimal128Ty(LLVMContext &C) { return &C.pImpl->Decimal128Ty; }
 Type *Type::getX86_MMXTy(LLVMContext &C) { return &C.pImpl->X86_MMXTy; }
 Type *Type::getX86_AMXTy(LLVMContext &C) { return &C.pImpl->X86_AMXTy; }
 
diff --git a/llvm/test/Assembler/dfp.ll b/llvm/test/Assembler/dfp.ll
new file mode 100644
index 000000000000000..8f93eef6836cbc2
--- /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