[cfe-commits] r105451 - in /cfe/trunk: lib/AST/ASTContext.cpp test/CodeGenObjC/bitfield_encoding.m

David Chisnall csdavec at swan.ac.uk
Thu Jun 3 18:10:52 PDT 2010


Author: theraven
Date: Thu Jun  3 20:10:52 2010
New Revision: 105451

URL: http://llvm.org/viewvc/llvm-project?rev=105451&view=rev
Log:
Fixed Objective-C type encoding for bitfields for the GNU runtime to match the encoding used by GCC.


Added:
    cfe/trunk/test/CodeGenObjC/bitfield_encoding.m
Modified:
    cfe/trunk/lib/AST/ASTContext.cpp

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=105451&r1=105450&r2=105451&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Jun  3 20:10:52 2010
@@ -3380,13 +3380,73 @@
                              true /* outermost type */);
 }
 
+static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
+    switch (T->getAs<BuiltinType>()->getKind()) {
+    default: assert(0 && "Unhandled builtin type kind");
+    case BuiltinType::Void:       return 'v';
+    case BuiltinType::Bool:       return 'B';
+    case BuiltinType::Char_U:
+    case BuiltinType::UChar:      return 'C';
+    case BuiltinType::UShort:     return 'S';
+    case BuiltinType::UInt:       return 'I';
+    case BuiltinType::ULong:
+        return
+          (const_cast<ASTContext *>(C))->getIntWidth(T) == 32 ? 'L' : 'Q';
+    case BuiltinType::UInt128:    return 'T';
+    case BuiltinType::ULongLong:  return 'Q';
+    case BuiltinType::Char_S:
+    case BuiltinType::SChar:      return 'c';
+    case BuiltinType::Short:      return 's';
+    case BuiltinType::Int:        return 'i';
+    case BuiltinType::Long:
+      return
+        (const_cast<ASTContext *>(C))->getIntWidth(T) == 32 ? 'l' : 'q';
+    case BuiltinType::LongLong:   return 'q';
+    case BuiltinType::Int128:     return 't';
+    case BuiltinType::Float:      return 'f';
+    case BuiltinType::Double:     return 'd';
+    case BuiltinType::LongDouble: return 'd';
+    }
+}
+
 static void EncodeBitField(const ASTContext *Context, std::string& S,
-                           const FieldDecl *FD) {
+                           QualType T, const FieldDecl *FD) {
   const Expr *E = FD->getBitWidth();
   assert(E && "bitfield width not there - getObjCEncodingForTypeImpl");
   ASTContext *Ctx = const_cast<ASTContext*>(Context);
-  unsigned N = E->EvaluateAsInt(*Ctx).getZExtValue();
   S += 'b';
+  // The NeXT runtime encodes bit fields as b followed by the number of bits.
+  // The GNU runtime requires more information; bitfields are encoded as b,
+  // then the offset (in bits) of the first element, then the type of the
+  // bitfield, then the size in bits.  For example, in this structure:
+  //
+  // struct
+  // {
+  //    int integer;
+  //    int flags:2;
+  // };
+  // On a 32-bit system, the encoding for flags would be b2 for the NeXT
+  // runtime, but b32i2 for the GNU runtime.  The reason for this extra
+  // information is not especially sensible, but we're stuck with it for
+  // compatibility with GCC, although providing it breaks anything that
+  // actually uses runtime introspection and wants to work on both runtimes...
+  if (!Ctx->getLangOptions().NeXTRuntime) {
+    const RecordDecl *RD = FD->getParent();
+    const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD);
+    // FIXME: This same linear search is also used in ExprConstant - it might
+    // be better if the FieldDecl stored its offset.  We'd be increasing the
+    // size of the object slightly, but saving some time every time it is used.
+    unsigned i = 0;
+    for (RecordDecl::field_iterator Field = RD->field_begin(),
+                                 FieldEnd = RD->field_end();
+         Field != FieldEnd; (void)++Field, ++i) {
+      if (*Field == FD)
+        break;
+    }
+    S += llvm::utostr(RL.getFieldOffset(i));
+    S += ObjCEncodingForPrimitiveKind(Context, T);
+  }
+  unsigned N = E->EvaluateAsInt(*Ctx).getZExtValue();
   S += llvm::utostr(N);
 }
 
@@ -3397,40 +3457,10 @@
                                             const FieldDecl *FD,
                                             bool OutermostType,
                                             bool EncodingProperty) {
-  if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
+  if (T->getAs<BuiltinType>()) {
     if (FD && FD->isBitField())
-      return EncodeBitField(this, S, FD);
-    char encoding;
-    switch (BT->getKind()) {
-    default: assert(0 && "Unhandled builtin type kind");
-    case BuiltinType::Void:       encoding = 'v'; break;
-    case BuiltinType::Bool:       encoding = 'B'; break;
-    case BuiltinType::Char_U:
-    case BuiltinType::UChar:      encoding = 'C'; break;
-    case BuiltinType::UShort:     encoding = 'S'; break;
-    case BuiltinType::UInt:       encoding = 'I'; break;
-    case BuiltinType::ULong:
-        encoding =
-          (const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'L' : 'Q';
-        break;
-    case BuiltinType::UInt128:    encoding = 'T'; break;
-    case BuiltinType::ULongLong:  encoding = 'Q'; break;
-    case BuiltinType::Char_S:
-    case BuiltinType::SChar:      encoding = 'c'; break;
-    case BuiltinType::Short:      encoding = 's'; break;
-    case BuiltinType::Int:        encoding = 'i'; break;
-    case BuiltinType::Long:
-      encoding =
-        (const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'l' : 'q';
-      break;
-    case BuiltinType::LongLong:   encoding = 'q'; break;
-    case BuiltinType::Int128:     encoding = 't'; break;
-    case BuiltinType::Float:      encoding = 'f'; break;
-    case BuiltinType::Double:     encoding = 'd'; break;
-    case BuiltinType::LongDouble: encoding = 'd'; break;
-    }
-
-    S += encoding;
+      return EncodeBitField(this, S, T, FD);
+    S += ObjCEncodingForPrimitiveKind(this, T);
     return;
   }
 
@@ -3589,7 +3619,7 @@
 
   if (T->isEnumeralType()) {
     if (FD && FD->isBitField())
-      EncodeBitField(this, S, FD);
+      EncodeBitField(this, S, T, FD);
     else
       S += 'i';
     return;

Added: cfe/trunk/test/CodeGenObjC/bitfield_encoding.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/bitfield_encoding.m?rev=105451&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/bitfield_encoding.m (added)
+++ cfe/trunk/test/CodeGenObjC/bitfield_encoding.m Thu Jun  3 20:10:52 2010
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o %t %s
+// RUN: grep "ib1b14" %t | count 1
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fgnu-runtime -emit-llvm -o %t %s
+// RUN: grep "ib32i1b33i14" %t | count 1
+
+struct foo{
+	int a;
+	int b:1;
+	int c:14;
+};
+
+const char *encoding = @encode(struct foo);





More information about the cfe-commits mailing list