[cfe-commits] r54395 - in /cfe/trunk: lib/CodeGen/CGExpr.cpp test/CodeGen/2008-07-22-packed-bitfield-access.c
Daniel Dunbar
daniel at zuster.org
Tue Aug 5 22:08:46 PDT 2008
Author: ddunbar
Date: Wed Aug 6 00:08:45 2008
New Revision: 54395
URL: http://llvm.org/viewvc/llvm-project?rev=54395&view=rev
Log:
Fix bitfield accesses which straddle the boundary of the underlying
type.
- This generates somewhat less optimal code than before but this is
not hard to rectify once stable (at the cost of slightly more
complex code).
- This currently always uses little-endian ordering of the bitfield.
- This breaks the CodeGen/bitfield.c test because it was grepping for
hard-coded assembly instructions. Will fix once a better test case
is constructed (hard to do without execution).
- This fixes SingleSource/UnitTests/2006-01-23-InitializedBitField.c
and Regression/C/PR1386.c from the test suite.
- <rdar://problem/6085090>, <rdar://problem/6094169>
Added:
cfe/trunk/test/CodeGen/2008-07-22-packed-bitfield-access.c
Modified:
cfe/trunk/lib/CodeGen/CGExpr.cpp
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=54395&r1=54394&r2=54395&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Aug 6 00:08:45 2008
@@ -173,28 +173,65 @@
RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
QualType ExprType) {
+ unsigned StartBit = LV.getBitfieldStartBit();
+ unsigned BitfieldSize = LV.getBitfieldSize();
llvm::Value *Ptr = LV.getBitfieldAddr();
- const llvm::Type *EltTy =
+
+ const llvm::Type *EltTy =
cast<llvm::PointerType>(Ptr->getType())->getElementType();
- unsigned EltTySize = EltTy->getPrimitiveSizeInBits();
- unsigned short BitfieldSize = LV.getBitfieldSize();
- unsigned short EndBit = LV.getBitfieldStartBit() + BitfieldSize;
-
- llvm::Value *V = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "tmp");
-
- llvm::Value *ShAmt = llvm::ConstantInt::get(EltTy, EltTySize - EndBit);
- V = Builder.CreateShl(V, ShAmt, "tmp");
-
- ShAmt = llvm::ConstantInt::get(EltTy, EltTySize - BitfieldSize);
- V = LV.isBitfieldSigned() ?
- Builder.CreateAShr(V, ShAmt, "tmp") :
- Builder.CreateLShr(V, ShAmt, "tmp");
+ unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy);
+
+ // In some cases the bitfield may straddle two memory locations.
+ // Currently we load the entire bitfield, then do the magic to
+ // sign-extend it if necessary. This results in somewhat more code
+ // than necessary for the common case (one load), since two shifts
+ // accomplish both the masking and sign extension.
+ unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit);
+ llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "tmp");
+
+ // Shift to proper location.
+ Val = Builder.CreateLShr(Val, llvm::ConstantInt::get(EltTy, StartBit),
+ "bf.lo");
+
+ // Mask off unused bits.
+ llvm::Constant *LowMask =
+ llvm::ConstantInt::get(llvm::APInt::getLowBitsSet(EltTySize, LowBits));
+ Val = Builder.CreateAnd(Val, LowMask, "bf.lo.cleared");
+
+ // Fetch the high bits if necessary.
+ if (LowBits < BitfieldSize) {
+ unsigned HighBits = BitfieldSize - LowBits;
+ llvm::Value *HighPtr =
+ Builder.CreateGEP(Ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, 1),
+ "bf.ptr.hi");
+ llvm::Value *HighVal = Builder.CreateLoad(HighPtr,
+ LV.isVolatileQualified(),
+ "tmp");
+
+ // Mask off unused bits.
+ llvm::Constant *HighMask =
+ llvm::ConstantInt::get(llvm::APInt::getLowBitsSet(EltTySize, HighBits));
+ HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared");
+
+ // Shift to proper location and or in to bitfield value.
+ HighVal = Builder.CreateShl(HighVal,
+ llvm::ConstantInt::get(EltTy, LowBits));
+ Val = Builder.CreateOr(Val, HighVal, "bf.val");
+ }
+
+ // Sign extend if necessary.
+ if (LV.isBitfieldSigned()) {
+ llvm::Value *ExtraBits = llvm::ConstantInt::get(EltTy,
+ EltTySize - BitfieldSize);
+ Val = Builder.CreateAShr(Builder.CreateShl(Val, ExtraBits),
+ ExtraBits, "bf.val.sext");
+ }
// The bitfield type and the normal type differ when the storage sizes
// differ (currently just _Bool).
- V = Builder.CreateIntCast(V, ConvertType(ExprType), false, "tmp");
+ Val = Builder.CreateIntCast(Val, ConvertType(ExprType), false, "tmp");
- return RValue::get(V);
+ return RValue::get(Val);
}
// If this is a reference to a subset of the elements of a vector, either
@@ -297,40 +334,73 @@
void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
QualType Ty) {
- unsigned short StartBit = Dst.getBitfieldStartBit();
- unsigned short BitfieldSize = Dst.getBitfieldSize();
+ unsigned StartBit = Dst.getBitfieldStartBit();
+ unsigned BitfieldSize = Dst.getBitfieldSize();
llvm::Value *Ptr = Dst.getBitfieldAddr();
- llvm::Value *NewVal = Src.getScalarVal();
- llvm::Value *OldVal = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(),
- "tmp");
-
- // The bitfield type and the normal type differ when the storage sizes
- // differ (currently just _Bool).
- const llvm::Type *EltTy = OldVal->getType();
- unsigned EltTySize = CGM.getTargetData().getABITypeSizeInBits(EltTy);
-
- NewVal = Builder.CreateIntCast(NewVal, EltTy, false, "tmp");
-
- // Move the bits into the appropriate location
- llvm::Value *ShAmt = llvm::ConstantInt::get(EltTy, StartBit);
- NewVal = Builder.CreateShl(NewVal, ShAmt, "tmp");
-
- llvm::Constant *Mask = llvm::ConstantInt::get(
- llvm::APInt::getBitsSet(EltTySize, StartBit,
- StartBit + BitfieldSize));
-
- // Mask out any bits that shouldn't be set in the result.
- NewVal = Builder.CreateAnd(NewVal, Mask, "tmp");
-
- // Next, mask out the bits this bit-field should include from the old value.
- Mask = llvm::ConstantExpr::getNot(Mask);
- OldVal = Builder.CreateAnd(OldVal, Mask, "tmp");
+ const llvm::Type *EltTy =
+ cast<llvm::PointerType>(Ptr->getType())->getElementType();
+ unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy);
- // Finally, merge the two together and store it.
- NewVal = Builder.CreateOr(OldVal, NewVal, "tmp");
+ // Get the new value, cast to the appropriate type and masked to
+ // exactly the size of the bit-field.
+ llvm::Value *NewVal = Src.getScalarVal();
+ NewVal = Builder.CreateIntCast(NewVal, EltTy, false, "tmp");
+ llvm::Constant *Mask =
+ llvm::ConstantInt::get(llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize));
+ NewVal = Builder.CreateAnd(NewVal, Mask, "bf.value");
+
+ // In some cases the bitfield may straddle two memory locations.
+ // Emit the low part first and check to see if the high needs to be
+ // done.
+ unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit);
+ llvm::Value *LowVal = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(),
+ "bf.prev.low");
+
+ // Compute the mask for zero-ing the low part of this bitfield.
+ llvm::Constant *InvMask =
+ llvm::ConstantInt::get(~llvm::APInt::getBitsSet(EltTySize, StartBit,
+ StartBit + LowBits));
+
+ // Compute the new low part as
+ // LowVal = (LowVal & InvMask) | (NewVal << StartBit),
+ // with the shift of NewVal implicitly stripping the high bits.
+ llvm::Value *NewLowVal =
+ Builder.CreateShl(NewVal, llvm::ConstantInt::get(EltTy, StartBit),
+ "bf.value.lo");
+ LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared");
+ LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo");
+
+ // Write back.
+ Builder.CreateStore(LowVal, Ptr, Dst.isVolatileQualified());
- Builder.CreateStore(NewVal, Ptr, Dst.isVolatileQualified());
+ // If the low part doesn't cover the bitfield emit a high part.
+ if (LowBits < BitfieldSize) {
+ unsigned HighBits = BitfieldSize - LowBits;
+ llvm::Value *HighPtr =
+ Builder.CreateGEP(Ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, 1),
+ "bf.ptr.hi");
+ llvm::Value *HighVal = Builder.CreateLoad(HighPtr,
+ Dst.isVolatileQualified(),
+ "bf.prev.hi");
+
+ // Compute the mask for zero-ing the high part of this bitfield.
+ llvm::Constant *InvMask =
+ llvm::ConstantInt::get(~llvm::APInt::getLowBitsSet(EltTySize, HighBits));
+
+ // Compute the new high part as
+ // HighVal = (HighVal & InvMask) | (NewVal lshr LowBits),
+ // where the high bits of NewVal have already been cleared and the
+ // shift stripping the low bits.
+ llvm::Value *NewHighVal =
+ Builder.CreateLShr(NewVal, llvm::ConstantInt::get(EltTy, LowBits),
+ "bf.value.high");
+ HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared");
+ HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi");
+
+ // Write back.
+ Builder.CreateStore(HighVal, HighPtr, Dst.isVolatileQualified());
+ }
}
void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
Added: cfe/trunk/test/CodeGen/2008-07-22-packed-bitfield-access.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/2008-07-22-packed-bitfield-access.c?rev=54395&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/2008-07-22-packed-bitfield-access.c (added)
+++ cfe/trunk/test/CodeGen/2008-07-22-packed-bitfield-access.c Wed Aug 6 00:08:45 2008
@@ -0,0 +1,10 @@
+// RUN: clang %s -emit-llvm -o -
+
+int main () {
+ struct foo {
+ unsigned a:16;
+ unsigned b:32 __attribute__ ((packed));
+ } x;
+ x.b = 0x56789abcL;
+ return 0;
+}
More information about the cfe-commits
mailing list