From ab970f90ce31a53fe7e6375a37536bf0832fd922 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Tue, 13 Apr 2010 20:58:55 +0000 Subject: [PATCH] IRgen: Enhance CGBitFieldInfo with enough information to fully describe the "policy" with which a bit-field should be accessed. - For now, these policies are computed to match the current IRgen strategy, although the new information isn't being used yet (except in -fdump-record-layouts). - Design comments appreciated. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101178 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGObjCMac.cpp | 11 ++++ lib/CodeGen/CGRecordLayout.h | 84 ++++++++++++++++++++++++++- lib/CodeGen/CGRecordLayoutBuilder.cpp | 70 ++++++++++++++++++++-- 3 files changed, 159 insertions(+), 6 deletions(-) diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 4713ac7ca2..8cd7cdbfe6 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -129,6 +129,17 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, new (CGF.CGM.getContext()) CGBitFieldInfo( LTy, FieldNo, BitOffset, BitFieldSize, IvarTy->isSignedIntegerType()); + // We always construct a single, possibly unaligned, access for this case. + Info->setNumComponents(1); + CGBitFieldInfo::AccessInfo &AI = Info->getComponent(0); + AI.FieldIndex = 0; + AI.FieldByteOffset = 0; + AI.FieldBitStart = BitOffset; + AI.AccessWidth = CGF.CGM.getContext().getTypeSize(IvarTy); + AI.AccessAlignment = 0; + AI.TargetBitOffset = 0; + AI.TargetBitWidth = BitFieldSize; + // FIXME: We need to set a very conservative alignment on this, or make sure // that the runtime is doing the right thing. return LValue::MakeBitfield(V, *Info, Quals.getCVRQualifiers()); diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index 2fb8191cf2..234f859118 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -20,9 +20,73 @@ namespace llvm { namespace clang { namespace CodeGen { -/// Helper object for describing how to generate the code for access to a +/// \brief Helper object for describing how to generate the code for access to a /// bit-field. +/// +/// This structure is intended to describe the "policy" of how the bit-field +/// should be accessed, which may be target, language, or ABI dependent. class CGBitFieldInfo { +public: + /// Descriptor for a single component of a bit-field access. The entire + /// bit-field is constituted of a bitwise OR of all of the individual + /// components. + /// + /// Each component describes an accessed value, which is how the component + /// should be transferred to/from memory, and a target placement, which is how + /// that component fits into the constituted bit-field. The pseudo-IR for a + /// load is: + /// + /// %0 = gep %base, 0, FieldIndex + /// %1 = gep (i8*) %0, FieldByteOffset + /// %2 = (i(AccessWidth) *) %1 + /// %3 = load %2, align AccessAlignment + /// %4 = shr %3, FieldBitStart + /// + /// and the composed bit-field is formed as the boolean OR of all accesses, + /// masked to TargetBitWidth bits and shifted to TargetBitOffset. + struct AccessInfo { + /// Offset of the field to load in the LLVM structure, if any. + unsigned FieldIndex; + + /// Byte offset from the field address, if any. This should generally be + /// unused as the cleanest IR comes from having a well-constructed LLVM type + /// with proper GEP instructions, but sometimes its use is required, for + /// example if an access is intended to straddle an LLVM field boundary. + unsigned FieldByteOffset; + + /// Bit offset in the accessed value to use. The width is implied by \see + /// TargetBitWidth. + unsigned FieldBitStart; + + /// Bit width of the memory access to perform. + unsigned AccessWidth; + + /// The alignment of the memory access, or 0 if the default alignment should + /// be used. + // + // FIXME: Remove use of 0 to encode default, instead have IRgen do the right + // thing when it generates the code, if avoiding align directives is + // desired. + unsigned AccessAlignment; + + /// Offset for the target value. + unsigned TargetBitOffset; + + /// Number of bits in the access that are destined for the bit-field. + unsigned TargetBitWidth; + }; + +private: + /// The number of access components to use. + unsigned NumComponents; + + /// The components to use to access the bit-field. We may need up to three + /// separate components to support up to i64 bit-field access (4 + 2 + 1 byte + /// accesses). + // + // FIXME: De-hardcode this, just allocate following the struct. + AccessInfo Components[3]; + public: CGBitFieldInfo(const llvm::Type *FieldTy, unsigned FieldNo, unsigned Start, unsigned Size, bool IsSigned) @@ -36,6 +100,24 @@ public: unsigned Size; bool IsSigned : 1; +public: + bool isSigned() const { return IsSigned; } + + unsigned getNumComponents() const { return NumComponents; } + void setNumComponents(unsigned Value) { + assert(Value < 4 && "Invalid number of components!"); + NumComponents = Value; + } + + const AccessInfo &getComponent(unsigned Index) const { + assert(Index < getNumComponents() && "Invalid access!"); + return Components[Index]; + } + AccessInfo &getComponent(unsigned Index) { + assert(Index < getNumComponents() && "Invalid access!"); + return Components[Index]; + } + void print(llvm::raw_ostream &OS) const; void dump() const; }; diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index ac6aae8bdc..45acb03450 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -150,12 +150,45 @@ static CGBitFieldInfo ComputeBitFieldInfo(CodeGenTypes &Types, uint64_t FieldOffset, uint64_t FieldSize) { const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(FD->getType()); - uint64_t TypeSizeInBits = Types.getTargetData().getTypeAllocSize(Ty) * 8; + uint64_t TypeSizeInBytes = Types.getTargetData().getTypeAllocSize(Ty); + uint64_t TypeSizeInBits = TypeSizeInBytes * 8; bool IsSigned = FD->getType()->isSignedIntegerType(); CGBitFieldInfo BFI(Ty, FieldOffset / TypeSizeInBits, FieldOffset % TypeSizeInBits, FieldSize, IsSigned); + // The current policy is to always access the bit-field using the source type + // of the bit-field. With the C bit-field rules, this implies that we always + // use either one or two accesses, and two accesses can only occur with a + // packed structure when the bit-field straddles an alignment boundary. + unsigned LowBits = std::min(FieldSize, TypeSizeInBits - BFI.Start); + bool NeedsHighAccess = LowBits != FieldSize; + BFI.setNumComponents(1 + NeedsHighAccess); + + // FIXME: This access policy is probably wrong on big-endian systems. + CGBitFieldInfo::AccessInfo &LowAccess = BFI.getComponent(0); + LowAccess.FieldIndex = 0; + LowAccess.FieldByteOffset = + TypeSizeInBytes * ((FieldOffset / 8) / TypeSizeInBytes); + LowAccess.FieldBitStart = BFI.Start; + LowAccess.AccessWidth = TypeSizeInBits; + // FIXME: This might be wrong! + LowAccess.AccessAlignment = 0; + LowAccess.TargetBitOffset = 0; + LowAccess.TargetBitWidth = LowBits; + + if (NeedsHighAccess) { + CGBitFieldInfo::AccessInfo &HighAccess = BFI.getComponent(1); + HighAccess.FieldIndex = 0; + HighAccess.FieldByteOffset = LowAccess.FieldByteOffset + TypeSizeInBytes; + HighAccess.FieldBitStart = 0; + HighAccess.AccessWidth = TypeSizeInBits; + // FIXME: This might be wrong! + HighAccess.AccessAlignment = 0; + HighAccess.TargetBitOffset = LowBits; + HighAccess.TargetBitWidth = FieldSize - LowBits; + } + return BFI; } @@ -500,8 +533,13 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) RL->BitFields.insert(Builder.LLVMBitFields[i]); - if (getContext().getLangOptions().DumpRecordLayouts) + if (getContext().getLangOptions().DumpRecordLayouts) { + llvm::errs() << "\n*** Dumping Record Layout\n"; + llvm::errs() << "Record: "; + D->dump(); + llvm::errs() << "\nLayout: "; RL->dump(); + } return RL; } @@ -514,7 +552,7 @@ void CGRecordLayout::print(llvm::raw_ostream &OS) const { for (llvm::DenseMap::const_iterator it = BitFields.begin(), ie = BitFields.end(); it != ie; ++it) { - OS << " "; + OS.indent(4); it->second.print(OS); OS << "\n"; } @@ -531,8 +569,30 @@ void CGBitFieldInfo::print(llvm::raw_ostream &OS) const { OS << " FieldNo:" << FieldNo; OS << " Start:" << Start; OS << " Size:" << Size; - OS << " IsSigned:" << IsSigned; - OS << ">"; + OS << " IsSigned:" << IsSigned << "\n"; + + OS.indent(4 + strlen("\n"; + } + OS.indent(4); + } + OS << "]>"; } void CGBitFieldInfo::dump() const { -- 2.40.0