diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index e03b112194786..ec344fb96f9d3 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1115,6 +1115,9 @@ class ASTContext : public RefCountedBase { CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON CanQualType BFloat16Ty; CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3 + // ISO/IEC TS 18661-2:2015 c23 conditionally supported + CanQualType DecimalFloat32Ty, DecimalFloat64Ty, DecimalFloat128Ty; + CanQualType DecimalFloatDPD32Ty, DecimalFloatDPD64Ty, DecimalFloatDPD128Ty; CanQualType VoidPtrTy, NullPtrTy; CanQualType DependentTy, OverloadTy, BoundMemberTy, UnresolvedTemplateTy, UnknownAnyTy; diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def index 444be4311a743..a99ef58b7e8ee 100644 --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -221,6 +221,19 @@ FLOATING_TYPE(Float128, Float128Ty) // '__ibm128' FLOATING_TYPE(Ibm128, Ibm128Ty) +// '_Decimal32' +FLOATING_TYPE(DecimalFloatBID32, DecimalFloat32Ty) +FLOATING_TYPE(DecimalFloatDPD32, DecimalFloatDPD32Ty) + +// '_Decimal64' +FLOATING_TYPE(DecimalFloatBID64, DecimalFloat64Ty) +FLOATING_TYPE(DecimalFloatDPD64, DecimalFloatDPD64Ty) + +// '_Decimal128' +FLOATING_TYPE(DecimalFloatBID128, DecimalFloat128Ty) +FLOATING_TYPE(DecimalFloatDPD128, DecimalFloatDPD128Ty) + + //===- Language-specific types --------------------------------------------===// // This is the type of C++0x 'nullptr'. diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 9cd7a364cd3f1..4edb04502f83e 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -460,10 +460,10 @@ class alignas(void *) Stmt { unsigned : NumExprBits; static_assert( - llvm::APFloat::S_MaxSemantics < 16, - "Too many Semantics enum values to fit in bitfield of size 4"); + llvm::APFloat::S_MaxSemantics < 32, + "Too many Semantics enum values to fit in bitfield of size 5"); LLVM_PREFERRED_TYPE(llvm::APFloat::Semantics) - unsigned Semantics : 4; // Provides semantics for APFloat construction + unsigned Semantics : 5; // Provides semantics for APFloat construction LLVM_PREFERRED_TYPE(bool) unsigned IsExact : 1; }; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index e6643469e0b33..cefde2398bab5 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2479,6 +2479,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { bool isBFloat16Type() const; bool isFloat128Type() const; bool isIbm128Type() const; + bool isDecimalFloatType() const; bool isRealType() const; // C99 6.2.5p17 (real floating + integer) bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) bool isVoidType() const; // C99 6.2.5p19 diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 8a6511b9ced83..d80aa1d742ee0 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -92,6 +92,9 @@ struct TransferrableTargetInfo { unsigned char FloatWidth, FloatAlign; unsigned char DoubleWidth, DoubleAlign; unsigned char LongDoubleWidth, LongDoubleAlign, Float128Align, Ibm128Align; + unsigned char DecimalFloat32Width, DecimalFloat32Align; + unsigned char DecimalFloat64Width, DecimalFloat64Align; + unsigned char DecimalFloat128Width, DecimalFloat128Align; unsigned char LargeArrayMinWidth, LargeArrayAlign; unsigned char LongWidth, LongAlign; unsigned char LongLongWidth, LongLongAlign; @@ -136,7 +139,9 @@ struct TransferrableTargetInfo { unsigned MaxTLSAlign; const llvm::fltSemantics *HalfFormat, *BFloat16Format, *FloatFormat, - *DoubleFormat, *LongDoubleFormat, *Float128Format, *Ibm128Format; + *DoubleFormat, *LongDoubleFormat, *Float128Format, *Ibm128Format, + *DecimalFloatBID32Format, *DecimalFloatBID64Format, *DecimalFloatBID128Format, + *DecimalFloatDPD32Format, *DecimalFloatDPD64Format, *DecimalFloatDPD128Format; ///===---- Target Data Type Query Methods -------------------------------===// enum IntType { @@ -794,6 +799,34 @@ class TargetInfo : public TransferrableTargetInfo, return *Float128Format; } + unsigned getDecimalFloat32Width() const { return 32; } + unsigned getDecimalFloat32Align() const { return DecimalFloat32Align; } + const llvm::fltSemantics &getDecimalFloatBID32Format() const { + return *DecimalFloatBID32Format; + } + const llvm::fltSemantics &getDecimalFloatDPD32Format() const { + return *DecimalFloatDPD32Format; + } + + unsigned getDecimalFloat64Width() const { return 64; } + unsigned getDecimalFloat64Align() const { return DecimalFloat64Align; } + const llvm::fltSemantics &getDecimalFloatBID64Format() const { + return *DecimalFloatBID64Format; + } + const llvm::fltSemantics &getDecimalFloatDPD64Format() const { + return *DecimalFloatDPD64Format; + } + + unsigned getDecimalFloat128Width() const { return 128; } + unsigned getDecimalFloat128Align() const { return DecimalFloat128Align; } + const llvm::fltSemantics &getDecimalFloatBID128Format() const { + return *DecimalFloatBID128Format; + } + const llvm::fltSemantics &getDecimalFloatDPD128Format() const { + return *DecimalFloatDPD128Format; + } + + /// getIbm128Width/Align/Format - Return the size/align/format of /// '__ibm128'. unsigned getIbm128Width() const { return 128; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4475f399a120b..94d19d196bc38 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1263,6 +1263,14 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, InitBuiltinType(SatUnsignedFractTy, BuiltinType::SatUFract); InitBuiltinType(SatUnsignedLongFractTy, BuiltinType::SatULongFract); + InitBuiltinType(DecimalFloat32Ty, BuiltinType::DecimalFloatBID32); + InitBuiltinType(DecimalFloat64Ty, BuiltinType::DecimalFloatBID64); + InitBuiltinType(DecimalFloat128Ty, BuiltinType::DecimalFloatBID128); + + InitBuiltinType(DecimalFloatDPD32Ty, BuiltinType::DecimalFloatDPD32); + InitBuiltinType(DecimalFloatDPD64Ty, BuiltinType::DecimalFloatDPD64); + InitBuiltinType(DecimalFloatDPD128Ty, BuiltinType::DecimalFloatDPD128); + // GNU extension, 128-bit integers. InitBuiltinType(Int128Ty, BuiltinType::Int128); InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); @@ -1628,6 +1636,18 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { if (getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice) return AuxTarget->getFloat128Format(); return Target->getFloat128Format(); + case BuiltinType::DecimalFloatBID32: + return Target->getDecimalFloatBID32Format(); + case BuiltinType::DecimalFloatDPD32: + return Target->getDecimalFloatDPD32Format(); + case BuiltinType::DecimalFloatBID64: + return Target->getDecimalFloatBID64Format(); + case BuiltinType::DecimalFloatDPD64: + return Target->getDecimalFloatDPD64Format(); + case BuiltinType::DecimalFloatBID128: + return Target->getDecimalFloatBID128Format(); + case BuiltinType::DecimalFloatDPD128: + return Target->getDecimalFloatDPD128Format(); } } @@ -2102,6 +2122,21 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getIbm128Width(); Align = Target->getIbm128Align(); break; + case BuiltinType::DecimalFloatBID32: + case BuiltinType::DecimalFloatDPD32: + Width = Target->getDecimalFloat32Width(); + Align = Target->getDecimalFloat32Align(); + break; + case BuiltinType::DecimalFloatBID64: + case BuiltinType::DecimalFloatDPD64: + Width = Target->getDecimalFloat64Width(); + Align = Target->getDecimalFloat64Align(); + break; + case BuiltinType::DecimalFloatBID128: + case BuiltinType::DecimalFloatDPD128: + Width = Target->getDecimalFloat128Width(); + Align = Target->getDecimalFloat128Align(); + break; case BuiltinType::LongDouble: if (getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice && (Target->getLongDoubleWidth() != AuxTarget->getLongDoubleWidth() || @@ -8140,6 +8175,12 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C, case BuiltinType::SatUShortFract: case BuiltinType::SatUFract: case BuiltinType::SatULongFract: + case BuiltinType::DecimalFloatBID32: + case BuiltinType::DecimalFloatDPD32: + case BuiltinType::DecimalFloatBID64: + case BuiltinType::DecimalFloatDPD64: + case BuiltinType::DecimalFloatBID128: + case BuiltinType::DecimalFloatDPD128: // FIXME: potentially need @encodes for these! return ' '; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index e31741cd44240..080005eb58ba5 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2238,12 +2238,19 @@ bool Type::hasUnsignedIntegerRepresentation() const { bool Type::isFloatingType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Half && - BT->getKind() <= BuiltinType::Ibm128; + BT->getKind() <= BuiltinType::DecimalFloatDPD128; if (const auto *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isFloatingType(); return false; } +bool Type::isDecimalFloatType() const { + if (const auto *BT = dyn_cast(CanonicalType)) + return BT->getKind() >= BuiltinType::DecimalFloatBID32 && + BT->getKind() <= BuiltinType::DecimalFloatDPD128; + return false; +} + bool Type::hasFloatingRepresentation() const { if (const auto *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isFloatingType(); @@ -2270,7 +2277,7 @@ bool Type::isRealType() const { bool Type::isArithmeticType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::Ibm128; + BT->getKind() <= BuiltinType::DecimalFloatDPD128; if (const auto *ET = dyn_cast(CanonicalType)) // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). // If a body isn't seen by the time we get here, return false. @@ -3379,6 +3386,15 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { return "__float128"; case Ibm128: return "__ibm128"; + case DecimalFloatBID32: + case DecimalFloatDPD32: + return "_Decimal32"; + case DecimalFloatBID64: + case DecimalFloatDPD64: + return "_Decimal64"; + case DecimalFloatBID128: + case DecimalFloatDPD128: + return "_Decimal128"; case WChar_S: case WChar_U: return Policy.MSWChar ? "__wchar_t" : "wchar_t"; diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 29f5cd14e46e1..2da4a3ad7ea04 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -147,6 +147,12 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) { LongDoubleFormat = &llvm::APFloat::IEEEdouble(); Float128Format = &llvm::APFloat::IEEEquad(); Ibm128Format = &llvm::APFloat::PPCDoubleDouble(); + DecimalFloatBID32Format = &llvm::APFloat::DFP32BID(); + DecimalFloatBID64Format = &llvm::APFloat::DFP64BID(); + DecimalFloatBID128Format = &llvm::APFloat::DFP128BID(); + DecimalFloatDPD32Format = &llvm::APFloat::DFP32DPD(); + DecimalFloatDPD64Format = &llvm::APFloat::DFP64DPD(); + DecimalFloatDPD128Format = &llvm::APFloat::DFP128DPD(); MCountName = "mcount"; UserLabelPrefix = "_"; RegParmMax = 0; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index eb67546d048ae..f3682fda178d7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1170,11 +1170,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.BoolTy; // _Bool or bool break; case DeclSpec::TST_decimal32: // _Decimal32 + Result = Context.DecimalFloat32Ty; + break; case DeclSpec::TST_decimal64: // _Decimal64 + Result = Context.DecimalFloat64Ty; + break; case DeclSpec::TST_decimal128: // _Decimal128 - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); - Result = Context.IntTy; - declarator.setInvalidType(true); + Result = Context.DecimalFloat128Ty; break; case DeclSpec::TST_class: case DeclSpec::TST_enum: diff --git a/clang/test/AST/dfp.c b/clang/test/AST/dfp.c new file mode 100644 index 0000000000000..d4224f03d881d --- /dev/null +++ b/clang/test/AST/dfp.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -x c -ast-dump %s | FileCheck %s --strict-whitespace + +_Decimal32 x; +_Decimal64 y; +_Decimal128 z; + +//CHECK: |-VarDecl {{.*}} x '_Decimal32' +//CHECK-NEXT: |-VarDecl {{.*}} y '_Decimal64' +//CHECK-NEXT: `-VarDecl {{.*}} z '_Decimal128' diff --git a/clang/test/Sema/types.c b/clang/test/Sema/types.c index e0a6ba4f0691b..d747f2b7d7cf1 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 x; +_Decimal64 y; +_Decimal128 z; int __attribute__ ((vector_size (8), vector_size (8))) v; // expected-error {{invalid vector element type}} diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index deb74cb2fdeb1..c393236998c69 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -146,6 +146,12 @@ struct APFloatBase { /// A signed type to represent a floating point numbers unbiased exponent. typedef int32_t ExponentType; + enum RadixAndFormat { + BaseTwo, + BaseTenBID, + BaseTenDPD + }; + /// \name Floating Point Semantics. /// @{ enum Semantics { @@ -190,7 +196,13 @@ struct APFloatBase { S_FloatTF32, S_x87DoubleExtended, - S_MaxSemantics = S_x87DoubleExtended, + S_DFP32BID, + S_DFP32DPD, + S_DFP64BID, + S_DFP64DPD, + S_DFP128BID, + S_DFP128DPD, + S_MaxSemantics = S_DFP128DPD, }; static const llvm::fltSemantics &EnumToSemantics(Semantics S); @@ -209,6 +221,12 @@ struct APFloatBase { static const fltSemantics &Float8E4M3B11FNUZ() LLVM_READNONE; static const fltSemantics &FloatTF32() LLVM_READNONE; static const fltSemantics &x87DoubleExtended() LLVM_READNONE; + static const fltSemantics &DFP32BID() LLVM_READNONE; + static const fltSemantics &DFP32DPD() LLVM_READNONE; + static const fltSemantics &DFP64BID() LLVM_READNONE; + static const fltSemantics &DFP64DPD() LLVM_READNONE; + static const fltSemantics &DFP128BID() LLVM_READNONE; + static const fltSemantics &DFP128DPD() LLVM_READNONE; /// A Pseudo fltsemantic used to construct APFloats that cannot conflict with /// anything real. @@ -773,6 +791,354 @@ hash_code hash_value(const DoubleAPFloat &Arg); DoubleAPFloat scalbn(const DoubleAPFloat &Arg, int Exp, IEEEFloat::roundingMode RM); DoubleAPFloat frexp(const DoubleAPFloat &X, int &Exp, IEEEFloat::roundingMode); +class DFPFloat final : public APFloatBase { +public: + /// \name Constructors + /// @{ + + DFPFloat(const fltSemantics &) {} // Default construct to +0.0 + DFPFloat(const fltSemantics &, integerPart) { assert(false && "Not Implemented"); } + DFPFloat(const fltSemantics &, uninitializedTag) { assert(false && "Not Implemented"); } + DFPFloat(const fltSemantics &, const APInt &) { assert(false && "Not Implemented"); } + explicit DFPFloat(double d) { assert(false && "Not Implemented"); } + explicit DFPFloat(float f) { assert(false && "Not Implemented"); } + DFPFloat(const DFPFloat &) { assert(false && "Not Implemented"); } + DFPFloat(DFPFloat &&) { assert(false && "Not Implemented"); } + ~DFPFloat() {} + + /// @} + + /// Returns whether this instance allocated memory. + bool needsCleanup() const { return partCount() > 1; } + + + /// \name Arithmetic + /// @{ + + opStatus add(const DFPFloat &, roundingMode); + opStatus subtract(const DFPFloat &, roundingMode); + opStatus multiply(const DFPFloat &, roundingMode); + opStatus divide(const DFPFloat &, roundingMode); + + opStatus remainder(const DFPFloat &); + + opStatus mod(const DFPFloat &); + opStatus fusedMultiplyAdd(const DFPFloat &, const DFPFloat &, roundingMode); + opStatus roundToIntegral(roundingMode); + + opStatus next(bool nextDown); + + /// @} + + /// \name Sign operations. + /// @{ + + void changeSign(); + + /// @} + + /// \name Conversions + /// @{ + + opStatus convert(const fltSemantics &, roundingMode, bool *); + opStatus convertToInteger(MutableArrayRef, unsigned int, bool, + roundingMode, bool *) const; + opStatus convertFromAPInt(const APInt &, bool, roundingMode); + opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int, + bool, roundingMode); + opStatus convertFromZeroExtendedInteger(const integerPart *, unsigned int, + bool, roundingMode); + Expected convertFromString(StringRef, roundingMode); + APInt bitcastToAPInt() const; + double convertToDouble() const; + float convertToFloat() const; + + /// @} + + + bool operator==(const IEEEFloat &) const = delete; + + + cmpResult compare(const IEEEFloat &) const; + + + bool bitwiseIsEqual(const IEEEFloat &) const; + + + unsigned int convertToHexString(char *dst, unsigned int hexDigits, + bool upperCase, roundingMode) const; + + + bool isNegative() const { return sign; } + + + bool isNormal() const { return !isDenormal() && isFiniteNonZero(); } + + + bool isFinite() const { return !isNaN() && !isInfinity(); } + + + bool isZero() const { return category == fcZero; } + + + bool isDenormal() const; + + + bool isInfinity() const { return category == fcInfinity; } + + + bool isNaN() const { return category == fcNaN; } + + + bool isSignaling() const; + + /// @} + + /// \name Simple Queries + /// @{ + + fltCategory getCategory() const { return category; } + const fltSemantics &getSemantics() const { return *semantics; } + bool isNonZero() const { return category != fcZero; } + bool isFiniteNonZero() const { return isFinite() && !isZero(); } + bool isPosZero() const { return isZero() && !isNegative(); } + bool isNegZero() const { return isZero() && isNegative(); } + + /// Returns true if and only if the number has the smallest possible non-zero + /// magnitude in the current semantics. + bool isSmallest() const; + + /// Returns true if this is the smallest (by magnitude) normalized finite + /// number in the given semantics. + bool isSmallestNormalized() const; + + /// Returns true if and only if the number has the largest possible finite + /// magnitude in the current semantics. + bool isLargest() const; + + /// Returns true if and only if the number is an exact integer. + bool isInteger() const; + + /// @} + + DFPFloat &operator=(const DFPFloat &); + DFPFloat &operator=(DFPFloat &&); + + /// Overload to compute a hash code for an DFPFloat value. + /// + friend hash_code hash_value(const DFPFloat &Arg); + + /// FIXME rewrite for DFP + /// Converts this value into a decimal string. + /// + /// \param FormatPrecision The maximum number of digits of + /// precision to output. If there are fewer digits available, + /// zero padding will not be used unless the value is + /// integral and small enough to be expressed in + /// FormatPrecision digits. 0 means to use the natural + /// precision of the number. + /// \param FormatMaxPadding The maximum number of zeros to + /// consider inserting before falling back to scientific + /// notation. 0 means to always use scientific notation. + /// + /// \param TruncateZero Indicate whether to remove the trailing zero in + /// fraction part or not. Also setting this parameter to false forcing + /// producing of output more similar to default printf behavior. + /// Specifically the lower e is used as exponent delimiter and exponent + /// always contains no less than two digits. + /// + /// Number Precision MaxPadding Result + /// ------ --------- ---------- ------ + /// 1.01E+4 5 2 10100 + /// 1.01E+4 4 2 1.01E+4 + /// 1.01E+4 5 1 1.01E+4 + /// 1.01E-2 5 2 0.0101 + /// 1.01E-2 4 2 0.0101 + /// 1.01E-2 4 1 1.01E-2 + void toString(SmallVectorImpl &Str, unsigned FormatPrecision = 0, + unsigned FormatMaxPadding = 3, bool TruncateZero = true) const; + + /// If this value has an exact multiplicative inverse, store it in inv and + /// return true. + bool getExactInverse(DFPFloat *inv) const; + + // If this is an exact power of two, return the exponent while ignoring the + // sign bit. If it's not an exact power of 2, return INT_MIN + LLVM_READONLY + int getExactLog2Abs() const; + + // If this is an exact power of two, return the exponent. If it's not an exact + // power of 2, return INT_MIN + LLVM_READONLY + int getExactLog2() const { + return isNegative() ? INT_MIN : getExactLog2Abs(); + } + + + friend int ilogb(const DFPFloat &Arg); + + + friend DFPFloat scalbn(DFPFloat X, int Exp, roundingMode); + + friend DFPFloat frexp(const DFPFloat &X, int &Exp, roundingMode); + + /// \name Special value setters. + /// @{ + + void makeLargest(bool Neg = false); + void makeSmallest(bool Neg = false); + void makeNaN(bool SNaN = false, bool Neg = false, + const APInt *fill = nullptr); + void makeInf(bool Neg = false); + void makeZero(bool Neg = false); + void makeQuiet(); + + /// Returns the smallest (by magnitude) normalized finite number in the given + /// semantics. + /// + /// \param Negative - True iff the number should be negative + void makeSmallestNormalized(bool Negative = false); + + /// @} + + cmpResult compareAbsoluteValue(const DFPFloat &) const; + +private: + /// \name Simple Queries + /// @{ + + integerPart *significandParts(); + const integerPart *significandParts() const; + unsigned int partCount() const; + + /// @} + + /// \name Significand operations. + /// @{ + + integerPart addSignificand(const DFPFloat &); + integerPart subtractSignificand(const DFPFloat &, integerPart); + lostFraction addOrSubtractSignificand(const DFPFloat &, bool subtract); + lostFraction multiplySignificand(const DFPFloat &, DFPFloat); + lostFraction multiplySignificand(const DFPFloat&); + lostFraction divideSignificand(const DFPFloat &); + void incrementSignificand(); + void initialize(const fltSemantics *); + void shiftSignificandLeft(unsigned int); + lostFraction shiftSignificandRight(unsigned int); + unsigned int significandLSB() const; + unsigned int significandMSB() const; + void zeroSignificand(); + /// Return true if the significand excluding the integral bit is all ones. + bool isSignificandAllOnes() const; + bool isSignificandAllOnesExceptLSB() const; + /// Return true if the significand excluding the integral bit is all zeros. + bool isSignificandAllZeros() const; + bool isSignificandAllZerosExceptMSB() const; + + /// @} + + /// \name Arithmetic on special values. + /// @{ + + opStatus addOrSubtractSpecials(const DFPFloat &, bool subtract); + opStatus divideSpecials(const DFPFloat &); + opStatus multiplySpecials(const DFPFloat &); + opStatus modSpecials(const DFPFloat &); + opStatus remainderSpecials(const DFPFloat&); + + /// @} + + /// \name Miscellany + /// @{ + + bool convertFromStringSpecials(StringRef str); + opStatus normalize(roundingMode, lostFraction); + opStatus addOrSubtract(const DFPFloat &, roundingMode, bool subtract); + opStatus handleOverflow(roundingMode); + bool roundAwayFromZero(roundingMode, lostFraction, unsigned int) const; + opStatus convertToSignExtendedInteger(MutableArrayRef, + unsigned int, bool, roundingMode, + bool *) const; + opStatus convertFromUnsignedParts(const integerPart *, unsigned int, + roundingMode); + Expected convertFromHexadecimalString(StringRef, roundingMode); + Expected convertFromDecimalString(StringRef, roundingMode); + char *convertNormalToHexString(char *, unsigned int, bool, + roundingMode) const; + opStatus roundSignificandWithExponent(const integerPart *, unsigned int, int, + roundingMode); + ExponentType exponentNaN() const; + ExponentType exponentInf() const; + ExponentType exponentZero() const; + + /// @} + + template APInt convertIEEEFloatToAPInt() const; + APInt convertHalfAPFloatToAPInt() const; + APInt convertBFloatAPFloatToAPInt() const; + APInt convertFloatAPFloatToAPInt() const; + APInt convertDoubleAPFloatToAPInt() const; + APInt convertQuadrupleAPFloatToAPInt() const; + APInt convertF80LongDoubleAPFloatToAPInt() const; + APInt convertPPCDoubleDoubleAPFloatToAPInt() const; + APInt convertFloat8E5M2APFloatToAPInt() const; + APInt convertFloat8E5M2FNUZAPFloatToAPInt() const; + APInt convertFloat8E4M3FNAPFloatToAPInt() const; + APInt convertFloat8E4M3FNUZAPFloatToAPInt() const; + APInt convertFloat8E4M3B11FNUZAPFloatToAPInt() const; + APInt convertFloatTF32APFloatToAPInt() const; + void initFromAPInt(const fltSemantics *Sem, const APInt &api); + template void initFromIEEEAPInt(const APInt &api); + void initFromHalfAPInt(const APInt &api); + void initFromBFloatAPInt(const APInt &api); + void initFromFloatAPInt(const APInt &api); + void initFromDoubleAPInt(const APInt &api); + void initFromQuadrupleAPInt(const APInt &api); + void initFromF80LongDoubleAPInt(const APInt &api); + void initFromPPCDoubleDoubleAPInt(const APInt &api); + void initFromFloat8E5M2APInt(const APInt &api); + void initFromFloat8E5M2FNUZAPInt(const APInt &api); + void initFromFloat8E4M3FNAPInt(const APInt &api); + void initFromFloat8E4M3FNUZAPInt(const APInt &api); + void initFromFloat8E4M3B11FNUZAPInt(const APInt &api); + void initFromFloatTF32APInt(const APInt &api); + + void assign(const DFPFloat &); + void copySignificand(const DFPFloat &); + void freeSignificand(); + + /// Note: this must be the first data member. + /// The semantics that this value obeys. + const fltSemantics *semantics; + + /// A binary fraction with an explicit integer bit. + /// + /// The significand must be at least one bit wider than the target precision. + union Significand { + integerPart part; + integerPart *parts; + } significand; + + /// The signed unbiased exponent of the value. + ExponentType exponent; + + /// What kind of floating point number this is. + /// + /// Only 2 bits are required, but VisualStudio incorrectly sign extends it. + /// Using the extra bit keeps it from failing under VisualStudio. + fltCategory category : 3; + + /// Sign bit of the number. + unsigned int sign : 1; +}; + +hash_code hash_value(const DFPFloat &Arg); +int ilogb(const DFPFloat &Arg); +DFPFloat scalbn(DFPFloat X, int Exp, DFPFloat::roundingMode); +DFPFloat frexp(const DFPFloat &Val, int &Exp, DFPFloat::roundingMode RM); + + } // End detail namespace // This is a interface class that is currently forwarding functionalities from @@ -780,6 +1146,7 @@ DoubleAPFloat frexp(const DoubleAPFloat &X, int &Exp, IEEEFloat::roundingMode); class APFloat : public APFloatBase { typedef detail::IEEEFloat IEEEFloat; typedef detail::DoubleAPFloat DoubleAPFloat; + typedef detail::DFPFloat DFPFloat; static_assert(std::is_standard_layout::value); diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h index 1f0133c08e7d6..551cf0d3be60e 100644 --- a/llvm/include/llvm/IR/Type.h +++ b/llvm/include/llvm/IR/Type.h @@ -60,6 +60,12 @@ class 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) + DecimalFloat32TyID, + DecimalFloatDPD32TyID, + DecimalFloat64TyID, + DecimalFloatDPD64TyID, + DecimalFloat128TyID, + DecimalFloatDPD128TyID, VoidTyID, ///< type with no size LabelTyID, ///< Labels MetadataTyID, ///< Metadata diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp index 72fedd8d67398..fa4b3906027c1 100644 --- a/llvm/lib/IR/LLVMContextImpl.cpp +++ b/llvm/lib/IR/LLVMContextImpl.cpp @@ -41,7 +41,11 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C) 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), - X86_AMXTy(C, Type::X86_AMXTyID), Int1Ty(C, 1), Int8Ty(C, 8), + X86_AMXTy(C, Type::X86_AMXTyID), + DecimalFloatBID32Ty(C, Type::DecimalFloat32TyID), DecimalFloatDPD32Ty(C, Type::DecimalFloatDPD32TyID), + DecimalFloatBID64Ty(C, Type::DecimalFloat64TyID), DecimalFloatDPD64Ty(C, Type::DecimalFloatDPD64TyID), + DecimalFloatBID128Ty(C, Type::DecimalFloat128TyID), DecimalFloatDPD128Ty(C, Type::DecimalFloatDPD128TyID), + Int1Ty(C, 1), Int8Ty(C, 8), Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), Int128Ty(C, 128) {} LLVMContextImpl::~LLVMContextImpl() { diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 399fe0dad26c7..5f764b3c8e733 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1573,6 +1573,8 @@ class LLVMContextImpl { Type VoidTy, LabelTy, HalfTy, BFloatTy, FloatTy, DoubleTy, MetadataTy, TokenTy; Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_MMXTy, X86_AMXTy; + Type DecimalFloatBID32Ty, DecimalFloatBID64Ty, DecimalFloatBID128Ty; + Type DecimalFloatDPD32Ty, DecimalFloatDPD64Ty, DecimalFloatDPD128Ty; IntegerType Int1Ty, Int8Ty, Int16Ty, Int32Ty, Int64Ty, Int128Ty; std::unique_ptr TheNoneToken; diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 2a9b3903720be..d30103c240b08 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -112,9 +112,13 @@ struct fltSemantics { /* Number of bits actually used in the semantics. */ unsigned int sizeInBits; + APFloatBase::RadixAndFormat radixAndFormat = APFloatBase::BaseTwo; + fltNonfiniteBehavior nonFiniteBehavior = fltNonfiniteBehavior::IEEE754; fltNanEncoding nanEncoding = fltNanEncoding::IEEE; + + // Returns true if any number described by this semantics can be precisely // represented by the specified semantics. Does not take into account // the value of fltNonfiniteBehavior. @@ -131,15 +135,21 @@ static constexpr fltSemantics semIEEEdouble = {1023, -1022, 53, 64}; static constexpr fltSemantics semIEEEquad = {16383, -16382, 113, 128}; static constexpr fltSemantics semFloat8E5M2 = {15, -14, 3, 8}; static constexpr fltSemantics semFloat8E5M2FNUZ = { - 15, -15, 3, 8, fltNonfiniteBehavior::NanOnly, fltNanEncoding::NegativeZero}; + 15, -15, 3, 8, APFloatBase::BaseTwo, fltNonfiniteBehavior::NanOnly, fltNanEncoding::NegativeZero}; static constexpr fltSemantics semFloat8E4M3FN = { - 8, -6, 4, 8, fltNonfiniteBehavior::NanOnly, fltNanEncoding::AllOnes}; + 8, -6, 4, 8, APFloatBase::BaseTwo,fltNonfiniteBehavior::NanOnly, fltNanEncoding::AllOnes}; static constexpr fltSemantics semFloat8E4M3FNUZ = { - 7, -7, 4, 8, fltNonfiniteBehavior::NanOnly, fltNanEncoding::NegativeZero}; + 7, -7, 4, 8, APFloatBase::BaseTwo, fltNonfiniteBehavior::NanOnly, fltNanEncoding::NegativeZero}; static constexpr fltSemantics semFloat8E4M3B11FNUZ = { - 4, -10, 4, 8, fltNonfiniteBehavior::NanOnly, fltNanEncoding::NegativeZero}; + 4, -10, 4, 8, APFloatBase::BaseTwo, fltNonfiniteBehavior::NanOnly, fltNanEncoding::NegativeZero}; static constexpr fltSemantics semFloatTF32 = {127, -126, 11, 19}; static constexpr fltSemantics semX87DoubleExtended = {16383, -16382, 64, 80}; +static constexpr fltSemantics semDFP32BID = {97, -94, 7, 32, APFloatBase::BaseTenBID}; +static constexpr fltSemantics semDFP32DPD = {97, -94, 7, 32, APFloatBase::BaseTenDPD}; +static constexpr fltSemantics semDFP64BID = {385, -382, 16, 64, APFloatBase::BaseTenBID}; +static constexpr fltSemantics semDFP64DPD = {385, -382, 16, 64, APFloatBase::BaseTenDPD}; +static constexpr fltSemantics semDFP128BID = {6145, -6142, 34, 128, APFloatBase::BaseTenBID}; +static constexpr fltSemantics semDFP128DPD = {6145, -6142, 34, 128, APFloatBase::BaseTenDPD}; static constexpr fltSemantics semBogus = {0, 0, 0, 0}; /* The IBM double-double semantics. Such a number consists of a pair of IEEE @@ -208,6 +218,19 @@ const llvm::fltSemantics &APFloatBase::EnumToSemantics(Semantics S) { return FloatTF32(); case S_x87DoubleExtended: return x87DoubleExtended(); + case S_DFP32BID: + return DFP32BID(); + case S_DFP32DPD: + return DFP32DPD(); + case S_DFP64BID: + return DFP64BID(); + case S_DFP64DPD: + return DFP64DPD(); + case S_DFP128BID: + return DFP128BID(); + case S_DFP128DPD: + return DFP128DPD(); + } llvm_unreachable("Unrecognised floating semantics"); } @@ -240,6 +263,11 @@ APFloatBase::SemanticsToEnum(const llvm::fltSemantics &Sem) { return S_FloatTF32; else if (&Sem == &llvm::APFloat::x87DoubleExtended()) return S_x87DoubleExtended; + else if (&Sem == &llvm::APFloat::DFP32BID()) + return S_DFP32BID; + else if (&Sem == &llvm::APFloat::DFP32DPD()) + return S_DFP32DPD; + else llvm_unreachable("Unknown floating semantics"); } @@ -263,6 +291,12 @@ const fltSemantics &APFloatBase::FloatTF32() { return semFloatTF32; } const fltSemantics &APFloatBase::x87DoubleExtended() { return semX87DoubleExtended; } +const fltSemantics &APFloatBase::DFP32BID() {return semDFP32BID;} +const fltSemantics &APFloatBase::DFP32DPD() {return semDFP32DPD;} +const fltSemantics &APFloatBase::DFP64BID() {return semDFP64BID;} +const fltSemantics &APFloatBase::DFP64DPD() {return semDFP64DPD;} +const fltSemantics &APFloatBase::DFP128BID() {return semDFP128BID;} +const fltSemantics &APFloatBase::DFP128DPD() {return semDFP128DPD;} const fltSemantics &APFloatBase::Bogus() { return semBogus; } constexpr RoundingMode APFloatBase::rmNearestTiesToEven; @@ -316,6 +350,8 @@ unsigned int APFloatBase::semanticsIntSizeInBits(const fltSemantics &semantics, bool APFloatBase::isRepresentableAsNormalIn(const fltSemantics &Src, const fltSemantics &Dst) { + // FIXME implement for DFP + // Exponent range must be larger. if (Src.maxExponent >= Dst.maxExponent || Src.minExponent <= Dst.minExponent) return false; @@ -332,6 +368,10 @@ unsigned APFloatBase::getSizeInBits(const fltSemantics &Sem) { return Sem.sizeInBits; } +APFloatBase::RadixAndFormat getRadixAndFormat(const fltSemantics &Sem) { + return Sem.radixAndFormat; +} + static constexpr APFloatBase::ExponentType exponentZero(const fltSemantics &semantics) { return semantics.minExponent - 1;