From 9a7a78b0ae3d50d73a920a40a28c6403bac03254 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Sun, 19 Apr 2009 02:03:42 +0000 Subject: [PATCH] Fix bug in computation of ivar offsets for (adjacent) bitfields. - The confusing IRgen bitfield interface is partly to blame here; fixing the functional error for now, cleanups to the interface to follow. llvm-svn: 69503 --- clang/lib/CodeGen/CGObjCMac.cpp | 23 +++++++++++-------- .../test/CodeGenObjC/bitfield-ivar-offsets.m | 23 +++++++++++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 clang/test/CodeGenObjC/bitfield-ivar-offsets.m diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 3a35ea4125af..0d6dd6aa776f 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -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/clang/test/CodeGenObjC/bitfield-ivar-offsets.m b/clang/test/CodeGenObjC/bitfield-ivar-offsets.m new file mode 100644 index 000000000000..0078a8c76a64 --- /dev/null +++ b/clang/test/CodeGenObjC/bitfield-ivar-offsets.m @@ -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