aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTContext.h15
-rw-r--r--include/clang/AST/Type.h24
-rw-r--r--lib/AST/ASTContext.cpp47
-rw-r--r--lib/AST/Type.cpp33
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp2
-rw-r--r--lib/Sema/SemaDeclAttr.cpp13
-rw-r--r--test/Sema/128bitint.c6
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];