diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 15 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 24 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 47 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 33 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 13 | ||||
-rw-r--r-- | test/Sema/128bitint.c | 6 |
7 files changed, 125 insertions, 15 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index bc0f191fd6..3f9e6bf213 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -78,7 +78,10 @@ class ASTContext { llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts; llvm::DenseMap<const ObjCInterfaceDecl*, const ASTRecordLayout*> ASTObjCInterfaces; - + + llvm::DenseMap<unsigned, FixedWidthIntType*> SignedFixedWidthIntTypes; + llvm::DenseMap<unsigned, FixedWidthIntType*> UnsignedFixedWidthIntTypes; + // FIXME: Shouldn't ASTRecordForInterface/ASTFieldForIvarRef and // addRecordToClass/getFieldDecl be part of the backend (i.e. CodeGenTypes and // CodeGenFunction)? @@ -369,7 +372,9 @@ public: void setBuiltinVaListType(QualType T); QualType getBuiltinVaListType() const { return BuiltinVaListType; } - + + QualType getFixedWidthIntType(unsigned Width, bool Signed); + private: QualType getFromTargetType(unsigned Type) const; @@ -532,6 +537,12 @@ public: QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize, QualType typeDomain) const; +private: + // Helper for integer ordering + unsigned getIntegerRank(Type* T); + +public: + //===--------------------------------------------------------------------===// // Type Compatibility Predicates //===--------------------------------------------------------------------===// diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 39e1495cd9..b93b06ba1e 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -251,7 +251,8 @@ public: ObjCInterface, ObjCQualifiedInterface, ObjCQualifiedId, TypeOfExp, TypeOfTyp, // GNU typeof extension. - BlockPointer // C extension + BlockPointer, // C extension + FixedWidthInt }; private: QualType CanonicalType; @@ -537,6 +538,27 @@ public: static bool classof(const BuiltinType *) { return true; } }; +/// FixedWidthIntType - Used for arbitrary width types that we either don't +/// want to or can't map to named integer types. These always have a lower +/// integer rank than builtin types of the same width. +class FixedWidthIntType : public Type { +private: + unsigned Width; + bool Signed; +public: + FixedWidthIntType(unsigned W, bool S) : Type(FixedWidthInt, QualType(), false), + Width(W), Signed(S) {} + + unsigned getWidth() const { return Width; } + bool isSigned() const { return Signed; } + const char *getName() const; + + virtual void getAsStringInternal(std::string &InnerString) const; + + static bool classof(const Type *T) { return T->getTypeClass() == FixedWidthInt; } + static bool classof(const FixedWidthIntType *) { return true; } +}; + /// ComplexType - C99 6.2.5p11 - Complex values. This supports the C99 complex /// types (_Complex float etc) as well as the GCC integer complex extensions. /// diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c9531508e9..d4fe26ed67 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -373,6 +373,13 @@ ASTContext::getTypeInfo(const Type *T) { break; } break; + case Type::FixedWidthInt: + // FIXME: This isn't precisely correct; the width/alignment should depend + // on the available types for the target + Width = cast<FixedWidthIntType>(T)->getWidth(); + Width = std::max(llvm::NextPowerOf2(Width - 1), 8ULL); + Align = Width; + break; case Type::ASQual: // FIXME: Pointers into different addr spaces could have different sizes and // alignment requirements: getPointerInfo should take an AddrSpace. @@ -769,6 +776,14 @@ QualType ASTContext::getComplexType(QualType T) { return QualType(New, 0); } +QualType ASTContext::getFixedWidthIntType(unsigned Width, bool Signed) { + llvm::DenseMap<unsigned, FixedWidthIntType*> &Map = Signed ? + SignedFixedWidthIntTypes : UnsignedFixedWidthIntTypes; + FixedWidthIntType *&Entry = Map[Width]; + if (!Entry) + Entry = new FixedWidthIntType(Width, Signed); + return QualType(Entry, 0); +} /// getPointerType - Return the uniqued reference to the type for a pointer to /// the specified type. @@ -1599,32 +1614,39 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { /// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This /// routine will assert if passed a built-in type that isn't an integer or enum, /// or if it is not canonicalized. -static unsigned getIntegerRank(Type *T) { +unsigned ASTContext::getIntegerRank(Type *T) { assert(T->isCanonical() && "T should be canonicalized"); - if (isa<EnumType>(T)) - return 4; - + if (EnumType* ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getIntegerType().getTypePtr(); + + // There are two things which impact the integer rank: the width, and + // the ordering of builtins. The builtin ordering is encoded in the + // bottom three bits; the width is encoded in the bits above that. + if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) { + return FWIT->getWidth() << 3; + } + switch (cast<BuiltinType>(T)->getKind()) { default: assert(0 && "getIntegerRank(): not a built-in integer"); case BuiltinType::Bool: - return 1; + return 1 + (getIntWidth(BoolTy) << 3); case BuiltinType::Char_S: case BuiltinType::Char_U: case BuiltinType::SChar: case BuiltinType::UChar: - return 2; + return 2 + (getIntWidth(CharTy) << 3); case BuiltinType::Short: case BuiltinType::UShort: - return 3; + return 3 + (getIntWidth(ShortTy) << 3); case BuiltinType::Int: case BuiltinType::UInt: - return 4; + return 4 + (getIntWidth(IntTy) << 3); case BuiltinType::Long: case BuiltinType::ULong: - return 5; + return 5 + (getIntWidth(LongTy) << 3); case BuiltinType::LongLong: case BuiltinType::ULongLong: - return 6; + return 6 + (getIntWidth(LongLongTy) << 3); } } @@ -2718,7 +2740,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { unsigned ASTContext::getIntWidth(QualType T) { if (T == BoolTy) return 1; - // At the moment, only bool has padding bits + if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) { + return FWIT->getWidth(); + } + // For builtin types, just use the standard type sizing method return (unsigned)getTypeSize(T); } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 24cf853555..ad5026b98b 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -510,6 +510,8 @@ bool Type::isIntegerType() const { // FIXME: In C++, enum types are never integer types. if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) return true; + if (isa<FixedWidthIntType>(CanonicalType)) + return true; if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isIntegerType(); if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) @@ -525,6 +527,8 @@ bool Type::isIntegralType() const { if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) return true; // Complete enum types are integral. // FIXME: In C++, enum types are never integral. + if (isa<FixedWidthIntType>(CanonicalType)) + return true; if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) return ASQT->getBaseType()->isIntegralType(); return false; @@ -578,6 +582,10 @@ bool Type::isSignedIntegerType() const { if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + if (const FixedWidthIntType *FWIT = + dyn_cast<FixedWidthIntType>(CanonicalType)) + return FWIT->isSigned(); + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) @@ -598,6 +606,10 @@ bool Type::isUnsignedIntegerType() const { if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + if (const FixedWidthIntType *FWIT = + dyn_cast<FixedWidthIntType>(CanonicalType)) + return !FWIT->isSigned(); + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) @@ -635,6 +647,8 @@ bool Type::isRealType() const { BT->getKind() <= BuiltinType::LongDouble; if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) return TT->getDecl()->isEnum() && TT->getDecl()->isDefinition(); + if (isa<FixedWidthIntType>(CanonicalType)) + return true; if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isRealType(); if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) @@ -650,6 +664,8 @@ bool Type::isArithmeticType() const { // 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. return ET->getDecl()->isDefinition(); + if (isa<FixedWidthIntType>(CanonicalType)) + return true; if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) return ASQT->getBaseType()->isArithmeticType(); return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType); @@ -667,6 +683,8 @@ bool Type::isScalarType() const { } if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) return ASQT->getBaseType()->isScalarType(); + if (isa<FixedWidthIntType>(CanonicalType)) + return true; return isa<PointerType>(CanonicalType) || isa<BlockPointerType>(CanonicalType) || isa<MemberPointerType>(CanonicalType) || @@ -1014,6 +1032,21 @@ void BuiltinType::getAsStringInternal(std::string &S) const { } } +void FixedWidthIntType::getAsStringInternal(std::string &S) const { + // FIXME: Once we get bitwidth attribute, write as + // "int __attribute__((bitwidth(x)))". + std::string prefix = "__clang_fixedwidth"; + prefix += llvm::utostr_32(Width); + prefix += (char)(Signed ? 'S' : 'U'); + if (S.empty()) { + S = prefix; + } else { + // Prefix the basic type, e.g. 'int X'. + S = prefix + S; + } +} + + void ComplexType::getAsStringInternal(std::string &S) const { ElementType->getAsStringInternal(S); S = "_Complex " + S; diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 37b7c5f68c..5c4b2a5900 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -216,6 +216,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { } break; } + case Type::FixedWidthInt: + return llvm::IntegerType::get(cast<FixedWidthIntType>(T)->getWidth()); case Type::Complex: { const llvm::Type *EltTy = ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType()); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index c27df2bdeb..c08634c788 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1238,7 +1238,12 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - // FIXME: Need proper fixed-width types + // FIXME: Sync this with InitializePredefinedMacros; we need to match + // int8_t and friends, at least with glibc. + // FIXME: Make sure 32/64-bit integers don't get defined to types of + // the wrong width on unusual platforms. + // FIXME: Make sure floating-point mappings are accurate + // FIXME: Support XF and TF types QualType NewTy; switch (DestWidth) { case 0: @@ -1277,6 +1282,12 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { else NewTy = S.Context.UnsignedLongLongTy; break; + case 128: + if (!IntegerMode) { + S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name; + return; + } + NewTy = S.Context.getFixedWidthIntType(128, OldTy->isSignedIntegerType()); } if (!OldTy->getAsBuiltinType()) diff --git a/test/Sema/128bitint.c b/test/Sema/128bitint.c new file mode 100644 index 0000000000..45678e90a9 --- /dev/null +++ b/test/Sema/128bitint.c @@ -0,0 +1,6 @@ +// RUN: clang -fsyntax-only -verify %s +typedef int i128 __attribute__((__mode__(TI))); +typedef unsigned u128 __attribute__((__mode__(TI))); + +int a[((i128)-1 ^ (i128)-2) == 1 ? 1 : -1]; +int a[(u128)-1 > 1LL ? 1 : -1]; |