From: Eli Friedman Date: Wed, 27 Jun 2012 21:19:48 +0000 (+0000) Subject: Propagate lvalue alignment into bitfields. Per report on cfe-dev. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f4bcfa1b1850711d5eb092f2b0639331ef9f09f1;p=clang Propagate lvalue alignment into bitfields. Per report on cfe-dev. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159295 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index c8563d6044..cb446dfeb4 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1047,6 +1047,9 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) { llvm::Value *Res = 0; for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); + CharUnits AccessAlignment = AI.AccessAlignment; + if (!LV.getAlignment().isZero()) + AccessAlignment = std::min(AccessAlignment, LV.getAlignment()); // Get the field pointer. llvm::Value *Ptr = LV.getBitFieldBaseAddr(); @@ -1070,8 +1073,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) { // Perform the load. llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified()); - if (!AI.AccessAlignment.isZero()) - Load->setAlignment(AI.AccessAlignment.getQuantity()); + Load->setAlignment(AccessAlignment.getQuantity()); // Shift out unused low bits and mask out unused high bits. llvm::Value *Val = Load; @@ -1270,6 +1272,9 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // Iterate over the components, writing each piece to memory. for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); + CharUnits AccessAlignment = AI.AccessAlignment; + if (!Dst.getAlignment().isZero()) + AccessAlignment = std::min(AccessAlignment, Dst.getAlignment()); // Get the field pointer. llvm::Value *Ptr = Dst.getBitFieldBaseAddr(); @@ -1316,8 +1321,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // If necessary, load and OR in bits that are outside of the bit-field. if (AI.TargetBitWidth != AI.AccessWidth) { llvm::LoadInst *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified()); - if (!AI.AccessAlignment.isZero()) - Load->setAlignment(AI.AccessAlignment.getQuantity()); + Load->setAlignment(AccessAlignment.getQuantity()); // Compute the mask for zeroing the bits that are part of the bit-field. llvm::APInt InvMask = @@ -1331,8 +1335,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // Write the value. llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr, Dst.isVolatileQualified()); - if (!AI.AccessAlignment.isZero()) - Store->setAlignment(AI.AccessAlignment.getQuantity()); + Store->setAlignment(AccessAlignment.getQuantity()); } } @@ -2084,16 +2087,6 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { llvm_unreachable("Unhandled member declaration!"); } -LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value *BaseValue, - const FieldDecl *Field, - unsigned CVRQualifiers) { - const CGRecordLayout &RL = - CGM.getTypes().getCGRecordLayout(Field->getParent()); - const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field); - return LValue::MakeBitfield(BaseValue, Info, - Field->getType().withCVRQualifiers(CVRQualifiers)); -} - /// EmitLValueForAnonRecordField - Given that the field is a member of /// an anonymous struct or union buried inside a record, and given /// that the base value is a pointer to the enclosing record, derive @@ -2118,9 +2111,15 @@ LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue, LValue CodeGenFunction::EmitLValueForField(LValue base, const FieldDecl *field) { - if (field->isBitField()) - return EmitLValueForBitfield(base.getAddress(), field, - base.getVRQualifiers()); + if (field->isBitField()) { + const CGRecordLayout &RL = + CGM.getTypes().getCGRecordLayout(field->getParent()); + const CGBitFieldInfo &Info = RL.getBitFieldInfo(field); + QualType fieldType = + field->getType().withCVRQualifiers(base.getVRQualifiers()); + return LValue::MakeBitfield(base.getAddress(), Info, fieldType, + base.getAlignment()); + } const RecordDecl *rec = field->getParent(); QualType type = field->getType(); diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp index 0f5cbc19d6..7cf0ed236f 100644 --- a/lib/CodeGen/CGObjCRuntime.cpp +++ b/lib/CodeGen/CGObjCRuntime.cpp @@ -120,6 +120,8 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, uint64_t ContainingTypeAlign = CGF.CGM.getContext().getTargetInfo().getCharAlign(); uint64_t ContainingTypeSize = TypeSizeInBits - (FieldBitOffset - BitOffset); uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext()); + CharUnits ContainingTypeAlignCharUnits = + CGF.CGM.getContext().toCharUnitsFromBits(ContainingTypeAlign); // Allocate a new CGBitFieldInfo object to describe this access. // @@ -132,7 +134,8 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, ContainingTypeSize, ContainingTypeAlign)); return LValue::MakeBitfield(V, *Info, - IvarTy.withCVRQualifiers(CVRQualifiers)); + IvarTy.withCVRQualifiers(CVRQualifiers), + ContainingTypeAlignCharUnits); } namespace { diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index 25a0a508f1..94c822f49f 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -64,12 +64,7 @@ public: /// 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. + /// The alignment of the memory access, assuming the parent is aligned. CharUnits AccessAlignment; /// Offset for the target value. diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 382cbfd10d..d642ef8533 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -235,6 +235,8 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, uint64_t FieldSize, uint64_t ContainingTypeSizeInBits, unsigned ContainingTypeAlign) { + assert(ContainingTypeAlign && "Expected alignment to be specified"); + llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType()); CharUnits TypeSizeInBytes = CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty)); diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index ac704e7dca..dd9208f913 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -153,7 +153,7 @@ class LValue { private: void Initialize(QualType Type, Qualifiers Quals, - CharUnits Alignment = CharUnits(), + CharUnits Alignment, llvm::MDNode *TBAAInfo = 0) { this->Type = Type; this->Quals = Quals; @@ -295,12 +295,12 @@ public: /// access. static LValue MakeBitfield(llvm::Value *BaseValue, const CGBitFieldInfo &Info, - QualType type) { + QualType type, CharUnits Alignment) { LValue R; R.LVType = BitField; R.V = BaseValue; R.BitFieldInfo = &Info; - R.Initialize(type, type.getQualifiers()); + R.Initialize(type, type.getQualifiers(), Alignment); return R; } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index b26d174180..fd93fbbdd2 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2166,9 +2166,6 @@ public: llvm::Value* Base, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers); - LValue EmitLValueForBitfield(llvm::Value* Base, const FieldDecl* Field, - unsigned CVRQualifiers); - LValue EmitCXXConstructLValue(const CXXConstructExpr *E); LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E); LValue EmitLambdaLValue(const LambdaExpr *E); diff --git a/test/CodeGen/packed-nest-unpacked.c b/test/CodeGen/packed-nest-unpacked.c index 0ccc0c41b7..6097e3f32e 100644 --- a/test/CodeGen/packed-nest-unpacked.c +++ b/test/CodeGen/packed-nest-unpacked.c @@ -45,3 +45,21 @@ void test6() { // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast (%struct.X* getelementptr inbounds (%struct.Y* @g, i32 0, i32 1) to i8*), i8* %{{.*}}, i64 24, i32 1, i1 false) g.y = foo(); } + + +struct XBitfield { + unsigned b1 : 10; + unsigned b2 : 12; + unsigned b3 : 10; +}; +struct YBitfield { + char x; + struct XBitfield y; +} __attribute((packed)); +struct YBitfield gbitfield; + +unsigned test7() { + // CHECK: @test7 + // CHECK: load i32* bitcast (%struct.XBitfield* getelementptr inbounds (%struct.YBitfield* @gbitfield, i32 0, i32 1) to i32*), align 1 + return gbitfield.y.b2; +}