[cfe-commits] r64434 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/Type.h lib/AST/ASTContext.cpp lib/AST/Type.cpp lib/CodeGen/CodeGenTypes.cpp lib/Sema/SemaDeclAttr.cpp test/Sema/128bitint.c

Eli Friedman eli.friedman at gmail.com
Thu Feb 12 18:31:07 PST 2009


Author: efriedma
Date: Thu Feb 12 20:31:07 2009
New Revision: 64434

URL: http://llvm.org/viewvc/llvm-project?rev=64434&view=rev
Log:
Initial implementation of arbitrary fixed-width integer types.  
Currently only used for 128-bit integers.

Note that we can't use the fixed-width integer types for other integer 
modes without other changes because glibc headers redefines (u)int*_t 
and friends using the mode attribute.  For example, this means that uint64_t
has to be compatible with unsigned __attribute((mode(DI))), and 
uint64_t is currently defined to long long.  And I have a feeling we'll 
run into issues if we try to define uint64_t as something which isn't 
either long or long long.

This doesn't get the alignment right in most cases, including 
the 128-bit integer case; I'll file a PR shortly.  The gist of the issue 
is that the targets don't really expose the information necessary to 
figure out the alignment outside of the target description, so there's a 
non-trivial amount of work involved in getting it working right.  That 
said, the alignment used is conservative, so the only issue with the 
current implementation is ABI compatibility.

This makes it trivial to add some sort of "bitwidth" attribute to make 
arbitrary-width integers; I'll do that in a followup.

We could also use this for stuff like the following for compatibility 
with gcc, but I have a feeling it would be a better idea for clang to be 
consistent between C and C++ modes rather than follow gcc's example for 
C mode.
struct {unsigned long long x : 33;} x;
unsigned long long a(void) {return x.x+1;}


Added:
    cfe/trunk/test/Sema/128bitint.c
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=64434&r1=64433&r2=64434&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Feb 12 20:31:07 2009
@@ -78,7 +78,10 @@
   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 @@
   
   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 @@
   QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize, 
                                              QualType typeDomain) const;
 
+private:
+  // Helper for integer ordering
+  unsigned getIntegerRank(Type* T);
+
+public:
+
   //===--------------------------------------------------------------------===//
   //                    Type Compatibility Predicates
   //===--------------------------------------------------------------------===//

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=64434&r1=64433&r2=64434&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Thu Feb 12 20:31:07 2009
@@ -251,7 +251,8 @@
     ObjCInterface, ObjCQualifiedInterface,
     ObjCQualifiedId,
     TypeOfExp, TypeOfTyp, // GNU typeof extension.
-    BlockPointer          // C extension
+    BlockPointer,          // C extension
+    FixedWidthInt
   };
 private:
   QualType CanonicalType;
@@ -537,6 +538,27 @@
   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.
 ///

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=64434&r1=64433&r2=64434&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Feb 12 20:31:07 2009
@@ -373,6 +373,13 @@
       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 @@
   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 @@
 /// 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 @@
 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);
 }
 

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=64434&r1=64433&r2=64434&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Thu Feb 12 20:31:07 2009
@@ -510,6 +510,8 @@
     // 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 @@
     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 @@
   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 @@
   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 @@
            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 @@
     // 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 @@
   }
   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 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;

Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.cpp?rev=64434&r1=64433&r2=64434&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenTypes.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenTypes.cpp Thu Feb 12 20:31:07 2009
@@ -216,6 +216,8 @@
     }
     break;
   }
+  case Type::FixedWidthInt:
+    return llvm::IntegerType::get(cast<FixedWidthIntType>(T)->getWidth());
   case Type::Complex: {
     const llvm::Type *EltTy = 
       ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType());

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=64434&r1=64433&r2=64434&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Feb 12 20:31:07 2009
@@ -1238,7 +1238,12 @@
     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 @@
     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())

Added: cfe/trunk/test/Sema/128bitint.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/128bitint.c?rev=64434&view=auto

==============================================================================
--- cfe/trunk/test/Sema/128bitint.c (added)
+++ cfe/trunk/test/Sema/128bitint.c Thu Feb 12 20:31:07 2009
@@ -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];





More information about the cfe-commits mailing list