diff --git a/clang/CodeGen/CGExpr.cpp b/clang/CodeGen/CGExpr.cpp index cb0f42a645e7..9c7876830cb4 100644 --- a/clang/CodeGen/CGExpr.cpp +++ b/clang/CodeGen/CGExpr.cpp @@ -454,7 +454,7 @@ EmitOCUVectorElementExpr(const OCUVectorElementExpr *E) { } LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { - + llvm::Value *V; bool isUnion = false; Expr *BaseExpr = E->getBase(); llvm::Value *BaseValue = NULL; @@ -476,14 +476,27 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { } FieldDecl *Field = E->getMemberDecl(); - unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); - llvm::Value *Idxs[2] = { llvm::Constant::getNullValue(llvm::Type::Int32Ty), - llvm::ConstantInt::get(llvm::Type::Int32Ty, idx) }; - llvm::Value *V = Builder.CreateGEP(BaseValue,Idxs, Idxs + 2, "tmp"); + + if (Field->isBitField()) { + const llvm::Type * FieldTy = ConvertType(Field->getType()); + const llvm::PointerType * BaseTy = + cast(BaseValue->getType()); + unsigned AS = BaseTy->getAddressSpace(); + BaseValue = Builder.CreateBitCast(BaseValue, + llvm::PointerType::get(FieldTy, AS), + "tmp"); + V = Builder.CreateGEP(BaseValue, + llvm::ConstantInt::get(llvm::Type::Int32Ty, idx), + "tmp"); + } else { + llvm::Value *Idxs[2] = { llvm::Constant::getNullValue(llvm::Type::Int32Ty), + llvm::ConstantInt::get(llvm::Type::Int32Ty, idx) }; + V = Builder.CreateGEP(BaseValue,Idxs, Idxs + 2, "tmp"); + } // Match union field type. - if (isUnion || Field->isBitField()) { + if (isUnion) { const llvm::Type * FieldTy = ConvertType(Field->getType()); const llvm::PointerType * BaseTy = cast(BaseValue->getType()); diff --git a/clang/CodeGen/CodeGenTypes.cpp b/clang/CodeGen/CodeGenTypes.cpp index 93b441bc62b0..bed01eeb61bc 100644 --- a/clang/CodeGen/CodeGenTypes.cpp +++ b/clang/CodeGen/CodeGenTypes.cpp @@ -73,7 +73,6 @@ namespace { uint64_t llvmSize; llvm::SmallVector FieldDecls; std::vector LLVMFields; - llvm::SmallVector Offsets; llvm::SmallSet PaddingFields; }; } @@ -449,7 +448,6 @@ void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { llvmFieldNo = 0; Cursor = 0; LLVMFields.clear(); - Offsets.clear(); for (llvm::SmallVector::iterator I = FieldDecls.begin(), E = FieldDecls.end(); I != E; ++I) { @@ -499,7 +497,6 @@ void RecordOrganizer::addLLVMField(const llvm::Type *Ty, bool isPaddingField) { } unsigned TySize = CGT.getTargetData().getABITypeSizeInBits(Ty); - Offsets.push_back(llvmSize); llvmSize += TySize; if (isPaddingField) PaddingFields.insert(llvmFieldNo); @@ -555,51 +552,26 @@ void RecordOrganizer::placeBitField(const FieldDecl *FD) { assert (isBitField && "Invalid BitField size expression"); uint64_t BitFieldSize = FieldSize.getZExtValue(); - bool FoundPrevField = false; - unsigned TotalOffsets = Offsets.size(); const llvm::Type *Ty = CGT.ConvertType(FD->getType()); uint64_t TySize = CGT.getTargetData().getABITypeSizeInBits(Ty); - - if (!TotalOffsets) { - // Special case: the first field. - CGT.addFieldInfo(FD, llvmFieldNo); + + unsigned Idx = Cursor / TySize; + unsigned BitsLeft = TySize - (Cursor % TySize); + + if (BitsLeft >= BitFieldSize) { + // The bitfield fits in the last aligned field. + // This is : struct { char a; int CurrentField:10;}; + // where 'CurrentField' shares first field with 'a'. + CGT.addFieldInfo(FD, Idx); + CGT.addBitFieldInfo(FD, TySize - BitsLeft, BitFieldSize); + Cursor += BitFieldSize; + } else { + // Place the bitfield in a new LLVM field. + // This is : struct { char a; short CurrentField:10;}; + // where 'CurrentField' needs a new llvm field. + CGT.addFieldInfo(FD, Idx + 1); CGT.addBitFieldInfo(FD, 0, BitFieldSize); - addPaddingFields(BitFieldSize); - Cursor = BitFieldSize; - return; + Cursor = (Idx + 1) * TySize + BitFieldSize; } - - // Search for the last aligned field. - for (unsigned i = TotalOffsets; i != 0; --i) { - uint64_t O = Offsets[i - 1]; - if (O % TySize == 0) { - FoundPrevField = true; - if (TySize > (Cursor - O) && TySize - (Cursor - O) >= BitFieldSize) { - // The bitfield fits in the last aligned field. - // This is : struct { char a; int CurrentField:10;}; - // where 'CurrentField' shares first field with 'a'. - addPaddingFields(Cursor + BitFieldSize); - CGT.addFieldInfo(FD, i - 1); - CGT.addBitFieldInfo(FD, Cursor - O, BitFieldSize); - Cursor += BitFieldSize; - } else { - // Place the bitfield in a new LLVM field. - // This is : struct { char a; short CurrentField:10;}; - // where 'CurrentField' needs a new llvm field. - unsigned Padding = 0; - if (Cursor % TySize) { - Padding = TySize - (Cursor % TySize); - addPaddingFields(Cursor + Padding); - } - CGT.addFieldInfo(FD, llvmFieldNo); - CGT.addBitFieldInfo(FD, 0, BitFieldSize); - Cursor += Padding + BitFieldSize; - addPaddingFields(Cursor); - } - break; - } - } - - assert(FoundPrevField && - "Unable to find a place for bitfield in struct layout"); + addPaddingFields(Cursor); } diff --git a/clang/test/CodeGen/bitfield.c b/clang/test/CodeGen/bitfield.c index 70414a9c1e38..740c41c5369e 100644 --- a/clang/test/CodeGen/bitfield.c +++ b/clang/test/CodeGen/bitfield.c @@ -5,10 +5,12 @@ // RUN: grep "lshr i16 %tmp5, 9" %t1 // RUN: grep "and i32 %tmp, -8192" %t1 // RUN: grep "and i16 %tmp5, -32513" %t1 +// RUN: grep "getelementptr (i32\* bitcast (.struct.STestB2\* @stb2 to i32\*), i32 1)" %t1 // Test bitfield access struct STestB1 { int a:13; char b; unsigned short c:7;} stb1; +struct STestB2 { short a[3]; int b:15} stb2; int f() { return stb1.a + stb1.b + stb1.c; @@ -19,3 +21,12 @@ void g() { stb1.b = 10; stb1.c = 15; } + +int h() { + return stb2.a[1] + stb2.b; +} + +void i(){ + stb2.a[2] = -40; + stb2.b = 10; +}