[cfe-dev] Patch for arbitrary fixed-width integer types

Eli Friedman eli.friedman at gmail.com
Fri Feb 6 20:28:03 PST 2009


Patch attached.  The reason I'm sending this to cfe-dev rather than
just committing it is that it's a substantial new chunk of code, and I
want to make sure it's something we really want; the potential users
are rather limited.

The attached patch adds one user for the new fixed-width types: the
implementation of the mode attribute.  That said, this is probably
overkill for that particular use, and it might confuse code that uses
function overloading.

Another possible use is that there was a request on the list a while
ago for a way to declare integer types of arbitrary width; this patch
would make implementing that relatively easy.

Also, we could use this for gcc compatibility for testcases like the
following, although I'm not sure it's worthwhile:
struct {unsigned long long x : 33;} x;
unsigned long long a(void) {return x.x+1;}

-Eli
-------------- next part --------------
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h	(revision 64001)
+++ include/clang/AST/ASTContext.h	(working copy)
@@ -76,7 +76,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)?
@@ -362,7 +365,9 @@
   
   void setBuiltinVaListType(QualType T);
   QualType getBuiltinVaListType() const { return BuiltinVaListType; }
-    
+
+  QualType getFixedWidthIntType(unsigned Width, bool Signed);
+
 private:
   QualType getFromTargetType(unsigned Type) const;
 
@@ -512,6 +517,12 @@
   QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize, 
                                              QualType typeDomain) const;
 
+  private:
+  // Helper for integer ordering
+  unsigned getIntegerRank(Type* T);
+
+  public:
+
   //===--------------------------------------------------------------------===//
   //                    Type Compatibility Predicates
   //===--------------------------------------------------------------------===//
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h	(revision 64001)
+++ include/clang/AST/Type.h	(working copy)
@@ -249,7 +249,8 @@
     ObjCInterface, ObjCQualifiedInterface,
     ObjCQualifiedId,
     TypeOfExp, TypeOfTyp, // GNU typeof extension.
-    BlockPointer          // C extension
+    BlockPointer,          // C extension
+    FixedWidthInt
   };
 private:
   QualType CanonicalType;
@@ -534,6 +535,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.
 ///
Index: lib/CodeGen/CodeGenTypes.cpp
===================================================================
--- lib/CodeGen/CodeGenTypes.cpp	(revision 64001)
+++ lib/CodeGen/CodeGenTypes.cpp	(working copy)
@@ -215,6 +215,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());
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp	(revision 64001)
+++ lib/Sema/SemaDeclAttr.cpp	(working copy)
@@ -1201,34 +1201,30 @@
     return;
   case 8:
     assert(IntegerMode);
-    if (OldTy->isSignedIntegerType())
-      NewTy = S.Context.SignedCharTy;
-    else
-      NewTy = S.Context.UnsignedCharTy;
+    NewTy = S.Context.getFixedWidthIntType(8, OldTy->isSignedIntegerType());
     break;
   case 16:
     assert(IntegerMode);
-    if (OldTy->isSignedIntegerType())
-      NewTy = S.Context.ShortTy;
-    else
-      NewTy = S.Context.UnsignedShortTy;
+    NewTy = S.Context.getFixedWidthIntType(16, OldTy->isSignedIntegerType());
     break;
   case 32:
     if (!IntegerMode)
       NewTy = S.Context.FloatTy;
-    else if (OldTy->isSignedIntegerType())
-      NewTy = S.Context.IntTy;
-    else
-      NewTy = S.Context.UnsignedIntTy;
+    else 
+      NewTy = S.Context.getFixedWidthIntType(32, OldTy->isSignedIntegerType());
     break;
   case 64:
     if (!IntegerMode)
       NewTy = S.Context.DoubleTy;
-    else if (OldTy->isSignedIntegerType())
-      NewTy = S.Context.LongLongTy;
     else
-      NewTy = S.Context.UnsignedLongLongTy;
+      NewTy = S.Context.getFixedWidthIntType(64, OldTy->isSignedIntegerType());
     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())
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp	(revision 64001)
+++ lib/AST/Type.cpp	(working copy)
@@ -498,6 +498,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))
@@ -513,6 +515,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;
@@ -566,6 +570,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))
@@ -586,6 +594,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))
@@ -623,6 +635,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))
@@ -638,6 +652,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);
@@ -655,6 +671,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) ||
@@ -947,6 +965,17 @@
   }
 }
 
+void FixedWidthIntType::getAsStringInternal(std::string &S) const {
+  if (S.empty()) {
+    S = llvm::utostr_32(Width);
+  } else {
+    // Prefix the basic type, e.g. 'int X'.
+    S = ' ' + S;
+    S = llvm::utostr_32(Width) + S;
+  }
+}
+
+
 void ComplexType::getAsStringInternal(std::string &S) const {
   ElementType->getAsStringInternal(S);
   S = "_Complex " + S;
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp	(revision 64001)
+++ lib/AST/ASTContext.cpp	(working copy)
@@ -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,18 @@
   return QualType(New, 0);
 }
 
+QualType ASTContext::getFixedWidthIntType(unsigned Width, bool Signed) {
+  if (Signed) {
+    if (!SignedFixedWidthIntTypes.count(Width)) {
+      SignedFixedWidthIntTypes[Width] = new FixedWidthIntType(Width, true);
+    }
+    return QualType(SignedFixedWidthIntTypes[Width], 0);
+  }
+  if (!UnsignedFixedWidthIntTypes.count(Width)) {
+    UnsignedFixedWidthIntTypes[Width] = new FixedWidthIntType(Width, false);
+  }
+  return QualType(UnsignedFixedWidthIntTypes[Width], 0);
+}
 
 /// getPointerType - Return the uniqued reference to the type for a pointer to
 /// the specified type.
@@ -1571,32 +1590,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);
   }
 }
 
@@ -2658,7 +2684,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);
 }
 


More information about the cfe-dev mailing list