aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGExpr.cpp
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2012-12-06 11:14:44 +0000
committerChandler Carruth <chandlerc@gmail.com>2012-12-06 11:14:44 +0000
commit72d2dab6058467036df73a5f668036a519043e5b (patch)
treea0544e418f5ba7594ea2dcff9a6209eddcc7887f /lib/CodeGen/CGExpr.cpp
parent3b5943f535eca0e0b91f4bcda9d09c9c275cf855 (diff)
Rework the bitfield access IR generation to address PR13619 and
generally support the C++11 memory model requirements for bitfield accesses by relying more heavily on LLVM's memory model. The primary change this introduces is to move from a manually aligned and strided access pattern across the bits of the bitfield to a much simpler lump access of all bits in the bitfield followed by math to extract the bits relevant for the particular field. This simplifies the code significantly, but relies on LLVM to intelligently lowering these integers. I have tested LLVM's lowering both synthetically and in benchmarks. The lowering appears to be functional, and there are no really significant performance regressions. Different code patterns accessing bitfields will vary in how this impacts them. The only real regressions I'm seeing are a few patterns where the LLVM code generation for loads that feed directly into a mask operation don't take advantage of the x86 ability to do a smaller load and a cheap zero-extension. This doesn't regress any benchmark in the nightly test suite on my box past the noise threshold, but my box is quite noisy. I'll be watching the LNT numbers, and will look into further improvements to the LLVM lowering as needed. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@169489 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGExpr.cpp')
-rw-r--r--lib/CodeGen/CGExpr.cpp242
1 files changed, 88 insertions, 154 deletions
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index f0ee2343d4..94bc81c8f4 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -1155,72 +1155,30 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
// Get the output type.
llvm::Type *ResLTy = ConvertType(LV.getType());
- unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy);
-
- // Compute the result as an OR of all of the individual component accesses.
- 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();
-
- // Only offset by the field index if used, so that incoming values are not
- // required to be structures.
- if (AI.FieldIndex)
- Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
-
- // Offset by the byte offset, if used.
- if (!AI.FieldByteOffset.isZero()) {
- Ptr = EmitCastToVoidPtr(Ptr);
- Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset.getQuantity(),
- "bf.field.offs");
- }
-
- // Cast to the access type.
- llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(), AI.AccessWidth,
- CGM.getContext().getTargetAddressSpace(LV.getType()));
- Ptr = Builder.CreateBitCast(Ptr, PTy);
-
- // Perform the load.
- llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified());
- Load->setAlignment(AccessAlignment.getQuantity());
-
- // Shift out unused low bits and mask out unused high bits.
- llvm::Value *Val = Load;
- if (AI.FieldBitStart)
- Val = Builder.CreateLShr(Load, AI.FieldBitStart);
- Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(AI.AccessWidth,
- AI.TargetBitWidth),
- "bf.clear");
-
- // Extend or truncate to the target size.
- if (AI.AccessWidth < ResSizeInBits)
- Val = Builder.CreateZExt(Val, ResLTy);
- else if (AI.AccessWidth > ResSizeInBits)
- Val = Builder.CreateTrunc(Val, ResLTy);
- // Shift into place, and OR into the result.
- if (AI.TargetBitOffset)
- Val = Builder.CreateShl(Val, AI.TargetBitOffset);
- Res = Res ? Builder.CreateOr(Res, Val) : Val;
- }
-
- // If the bit-field is signed, perform the sign-extension.
- //
- // FIXME: This can easily be folded into the load of the high bits, which
- // could also eliminate the mask of high bits in some situations.
- if (Info.isSigned()) {
- unsigned ExtraBits = ResSizeInBits - Info.getSize();
- if (ExtraBits)
- Res = Builder.CreateAShr(Builder.CreateShl(Res, ExtraBits),
- ExtraBits, "bf.val.sext");
+ llvm::Value *Ptr = LV.getBitFieldAddr();
+ llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(),
+ "bf.load");
+ cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment);
+
+ if (Info.IsSigned) {
+ assert((Info.Offset + Info.Size) <= Info.StorageSize);
+ unsigned HighBits = Info.StorageSize - Info.Offset - Info.Size;
+ if (HighBits)
+ Val = Builder.CreateShl(Val, HighBits, "bf.shl");
+ if (Info.Offset + HighBits)
+ Val = Builder.CreateAShr(Val, Info.Offset + HighBits, "bf.ashr");
+ } else {
+ if (Info.Offset)
+ Val = Builder.CreateLShr(Val, Info.Offset, "bf.lshr");
+ if (Info.Offset + Info.Size < Info.StorageSize)
+ Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(Info.StorageSize,
+ Info.Size),
+ "bf.clear");
}
+ Val = Builder.CreateIntCast(Val, ResLTy, Info.IsSigned, "bf.cast");
- return RValue::get(Res);
+ return RValue::get(Val);
}
// If this is a reference to a subset of the elements of a vector, create an
@@ -1350,106 +1308,71 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit
void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
llvm::Value **Result) {
const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
-
- // Get the output type.
llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
- unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy);
+ llvm::Value *Ptr = Dst.getBitFieldAddr();
// Get the source value, truncated to the width of the bit-field.
llvm::Value *SrcVal = Src.getScalarVal();
- if (hasBooleanRepresentation(Dst.getType()))
- SrcVal = Builder.CreateIntCast(SrcVal, ResLTy, /*IsSigned=*/false);
-
- SrcVal = Builder.CreateAnd(SrcVal, llvm::APInt::getLowBitsSet(ResSizeInBits,
- Info.getSize()),
- "bf.value");
-
- // Return the new value of the bit-field, if requested.
- if (Result) {
- // Cast back to the proper type for result.
- llvm::Type *SrcTy = Src.getScalarVal()->getType();
- llvm::Value *ReloadVal = Builder.CreateIntCast(SrcVal, SrcTy, false,
- "bf.reload.val");
-
- // Sign extend if necessary.
- if (Info.isSigned()) {
- unsigned ExtraBits = ResSizeInBits - Info.getSize();
- if (ExtraBits)
- ReloadVal = Builder.CreateAShr(Builder.CreateShl(ReloadVal, ExtraBits),
- ExtraBits, "bf.reload.sext");
- }
+ // Cast the source to the storage type and shift it into place.
+ SrcVal = Builder.CreateIntCast(SrcVal,
+ Ptr->getType()->getPointerElementType(),
+ /*IsSigned=*/false);
+ llvm::Value *MaskedVal = SrcVal;
+
+ // See if there are other bits in the bitfield's storage we'll need to load
+ // and mask together with source before storing.
+ if (Info.StorageSize != Info.Size) {
+ assert(Info.StorageSize > Info.Size && "Invalid bitfield size.");
+ llvm::Value *Val = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(),
+ "bf.load");
+ cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment);
+
+ // Mask the source value as needed.
+ if (!hasBooleanRepresentation(Dst.getType()))
+ SrcVal = Builder.CreateAnd(SrcVal,
+ llvm::APInt::getLowBitsSet(Info.StorageSize,
+ Info.Size),
+ "bf.value");
+ MaskedVal = SrcVal;
+ if (Info.Offset)
+ SrcVal = Builder.CreateShl(SrcVal, Info.Offset, "bf.shl");
+
+ // Mask out the original value.
+ Val = Builder.CreateAnd(Val,
+ ~llvm::APInt::getBitsSet(Info.StorageSize,
+ Info.Offset,
+ Info.Offset + Info.Size),
+ "bf.clear");
- *Result = ReloadVal;
+ // Or together the unchanged values and the source value.
+ SrcVal = Builder.CreateOr(Val, SrcVal, "bf.set");
+ } else {
+ assert(Info.Offset == 0);
}
- // 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();
- unsigned addressSpace =
- cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
-
- // Only offset by the field index if used, so that incoming values are not
- // required to be structures.
- if (AI.FieldIndex)
- Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
-
- // Offset by the byte offset, if used.
- if (!AI.FieldByteOffset.isZero()) {
- Ptr = EmitCastToVoidPtr(Ptr);
- Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset.getQuantity(),
- "bf.field.offs");
- }
+ // Write the new value back out.
+ llvm::StoreInst *Store = Builder.CreateStore(SrcVal, Ptr,
+ Dst.isVolatileQualified());
+ Store->setAlignment(Info.StorageAlignment);
- // Cast to the access type.
- llvm::Type *AccessLTy =
- llvm::Type::getIntNTy(getLLVMContext(), AI.AccessWidth);
-
- llvm::Type *PTy = AccessLTy->getPointerTo(addressSpace);
- Ptr = Builder.CreateBitCast(Ptr, PTy);
-
- // Extract the piece of the bit-field value to write in this access, limited
- // to the values that are part of this access.
- llvm::Value *Val = SrcVal;
- if (AI.TargetBitOffset)
- Val = Builder.CreateLShr(Val, AI.TargetBitOffset);
- Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(ResSizeInBits,
- AI.TargetBitWidth));
-
- // Extend or truncate to the access size.
- if (ResSizeInBits < AI.AccessWidth)
- Val = Builder.CreateZExt(Val, AccessLTy);
- else if (ResSizeInBits > AI.AccessWidth)
- Val = Builder.CreateTrunc(Val, AccessLTy);
-
- // Shift into the position in memory.
- if (AI.FieldBitStart)
- Val = Builder.CreateShl(Val, AI.FieldBitStart);
-
- // 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());
- Load->setAlignment(AccessAlignment.getQuantity());
-
- // Compute the mask for zeroing the bits that are part of the bit-field.
- llvm::APInt InvMask =
- ~llvm::APInt::getBitsSet(AI.AccessWidth, AI.FieldBitStart,
- AI.FieldBitStart + AI.TargetBitWidth);
-
- // Apply the mask and OR in to the value to write.
- Val = Builder.CreateOr(Builder.CreateAnd(Load, InvMask), Val);
+ // Return the new value of the bit-field, if requested.
+ if (Result) {
+ llvm::Value *ResultVal = MaskedVal;
+
+ // Sign extend the value if needed.
+ if (Info.IsSigned) {
+ assert(Info.Size <= Info.StorageSize);
+ unsigned HighBits = Info.StorageSize - Info.Size;
+ if (HighBits) {
+ ResultVal = Builder.CreateShl(ResultVal, HighBits, "bf.result.shl");
+ ResultVal = Builder.CreateAShr(ResultVal, HighBits, "bf.result.ashr");
+ }
}
- // Write the value.
- llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr,
- Dst.isVolatileQualified());
- Store->setAlignment(AccessAlignment.getQuantity());
+ ResultVal = Builder.CreateIntCast(ResultVal, ResLTy, Info.IsSigned,
+ "bf.result.cast");
+ *Result = ResultVal;
}
}
@@ -2333,10 +2256,21 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
const CGRecordLayout &RL =
CGM.getTypes().getCGRecordLayout(field->getParent());
const CGBitFieldInfo &Info = RL.getBitFieldInfo(field);
+ llvm::Value *Addr = base.getAddress();
+ unsigned Idx = RL.getLLVMFieldNo(field);
+ if (Idx != 0)
+ // For structs, we GEP to the field that the record layout suggests.
+ Addr = Builder.CreateStructGEP(Addr, Idx, field->getName());
+ // Get the access type.
+ llvm::Type *PtrTy = llvm::Type::getIntNPtrTy(
+ getLLVMContext(), Info.StorageSize,
+ CGM.getContext().getTargetAddressSpace(base.getType()));
+ if (Addr->getType() != PtrTy)
+ Addr = Builder.CreateBitCast(Addr, PtrTy);
+
QualType fieldType =
field->getType().withCVRQualifiers(base.getVRQualifiers());
- return LValue::MakeBitfield(base.getAddress(), Info, fieldType,
- base.getAlignment());
+ return LValue::MakeBitfield(Addr, Info, fieldType, base.getAlignment());
}
const RecordDecl *rec = field->getParent();