Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed offline, I found codegen and lowering much simpler if we treated this like fixed point and acted as if it was a signed integer type. We may want to revisit this once we get to those tasks.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, neat, this comment survived the branch rebasing! Maybe all is not lost with respect to stacking and rebasing PRs!

I agree we may want to revisit this, but I think we should try to be consistent with the standard until we have a good indication that doing so isn't working in practice. It might make sense to introduce an isBinaryFloatingPoint() predicate and switch most existing uses of isFloatingPoint() (~330 uses) to it. Likewise for isFloatingType (~85 uses). I hope there won't be incentive to do similarly for isRealType() (~12 uses), isRealFloatingType() (~100 uses), and isArithmeticType() (~40 uses).

}

bool isSVEBool() const { return getKind() == Kind::SveBool; }
Expand Down
16 changes: 15 additions & 1 deletion clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {};
}
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Basic/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 7 additions & 2 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8531,15 +8531,20 @@ 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)
<< "_Float16";
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;
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
Expand All @@ -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':
Expand All @@ -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':
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
}
Expand Down
8 changes: 8 additions & 0 deletions clang/test/Driver/dfp-enablement-lang.c
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
87 changes: 83 additions & 4 deletions clang/test/Sema/dfp-types.c
Original file line number Diff line number Diff line change
@@ -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);
}
14 changes: 14 additions & 0 deletions clang/test/SemaCXX/dfp-types.cpp
Original file line number Diff line number Diff line change
@@ -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}}