]> granicus.if.org Git - clang/commitdiff
Fix bug in computation of ivar offsets for (adjacent) bitfields.
authorDaniel Dunbar <daniel@zuster.org>
Sun, 19 Apr 2009 02:03:42 +0000 (02:03 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Sun, 19 Apr 2009 02:03:42 +0000 (02:03 +0000)
 - The confusing IRgen bitfield interface is partly to blame here;
   fixing the functional error for now, cleanups to the interface to
   follow.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69503 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGObjCMac.cpp
test/CodeGenObjC/bitfield-ivar-offsets.m [new file with mode: 0644]

index 3a35ea4125af7c32e92fe07f08bdd70fa9fbb10c..0d6dd6aa776f6fd5605220dba75f90fbe2acd062 100644 (file)
@@ -1879,17 +1879,20 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
 uint64_t CGObjCCommonMac::GetIvarBaseOffset(const llvm::StructLayout *Layout,
                                             const FieldDecl *Field) {
   if (!Field->isBitField())
-    return Layout->getElementOffset(
-            CGM.getTypes().getLLVMFieldNo(Field));
+    return Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field));
+  
   // FIXME. Must be a better way of getting a bitfield base offset.
-  uint64_t offset = CGM.getTypes().getLLVMFieldNo(Field);
-  const llvm::Type *Ty = CGM.getTypes().ConvertTypeForMemRecursive(Field->getType());
-  uint64_t size = CGM.getTypes().getTargetData().getTypePaddedSizeInBits(Ty);
-  offset = (offset*size)/8; 
-  return offset;
+  CodeGenTypes::BitFieldInfo BFI = CGM.getTypes().getBitFieldInfo(Field);
+  // FIXME: The "field no" for bitfields is something completely
+  // different; it is the offset in multiples of the base type size!
+  uint64_t Offset = CGM.getTypes().getLLVMFieldNo(Field);
+  const llvm::Type *Ty = 
+    CGM.getTypes().ConvertTypeForMemRecursive(Field->getType());
+  Offset *= CGM.getTypes().getTargetData().getTypePaddedSizeInBits(Ty);
+  return (Offset + BFI.Begin) / 8;
 }
 
-/// GetFieldBaseOffset - return's field byt offset.
+/// GetFieldBaseOffset - return the field's byte offset.
 uint64_t CGObjCCommonMac::GetFieldBaseOffset(const ObjCInterfaceDecl *OI,
                                              const llvm::StructLayout *Layout,
                                              const FieldDecl *Field) {
@@ -4580,8 +4583,8 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
   for (RecordDecl::field_iterator e = RD->field_end(CGM.getContext()); 
        i != e; ++i) {
     FieldDecl *Field = *i;
-    uint64_t offset = GetIvarBaseOffset(Layout, Field);
-    Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), OIvars[iv++], offset);
+    Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), OIvars[iv++], 
+                                GetIvarBaseOffset(Layout, Field));
     if (Field->getIdentifier())
       Ivar[1] = GetMethodVarName(Field->getIdentifier());
     else
diff --git a/test/CodeGenObjC/bitfield-ivar-offsets.m b/test/CodeGenObjC/bitfield-ivar-offsets.m
new file mode 100644 (file)
index 0000000..0078a8c
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o %t %s &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b0" = global i64 0, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b1" = global i64 0, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b2" = global i64 1, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._x" = global i64 2, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b3" = global i64 4, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._y" = global i64 6, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b4" = global i64 7, section "__DATA, __objc_const", align 8' %t &&
+// RUN: true
+
+@interface I0 {
+  unsigned _b0:4;
+  unsigned _b1:5;
+  unsigned _b2:5;
+  char _x;
+  unsigned _b3:9;
+  char _y;
+  char _b4:3;
+}
+@end
+
+@implementation I0
+@end