aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CodeGen/CGExpr.cpp39
-rw-r--r--CodeGen/CodeGenFunction.h1
-rw-r--r--test/CodeGen/bitfield.c8
3 files changed, 46 insertions, 2 deletions
diff --git a/CodeGen/CGExpr.cpp b/CodeGen/CGExpr.cpp
index 9e907216ee..9abf1a4271 100644
--- a/CodeGen/CGExpr.cpp
+++ b/CodeGen/CGExpr.cpp
@@ -237,8 +237,11 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
// If this is an update of elements of a vector, insert them as appropriate.
if (Dst.isOCUVectorElt())
return EmitStoreThroughOCUComponentLValue(Src, Dst, Ty);
-
- assert(0 && "FIXME: Don't support store to bitfield yet");
+
+ if (Dst.isBitfield())
+ return EmitStoreThroughBitfieldLValue(Src, Dst, Ty);
+
+ assert(0 && "Unknown bitfield type");
}
llvm::Value *DstAddr = Dst.getAddress();
@@ -256,6 +259,38 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
Builder.CreateStore(Src.getScalarVal(), DstAddr);
}
+void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
+ QualType Ty) {
+ unsigned short StartBit = Dst.getBitfieldStartBit();
+ unsigned short BitfieldSize = Dst.getBitfieldSize();
+ llvm::Value *Ptr = Dst.getBitfieldAddr();
+ const llvm::Type *EltTy =
+ cast<llvm::PointerType>(Ptr->getType())->getElementType();
+ unsigned EltTySize = EltTy->getPrimitiveSizeInBits();
+
+ llvm::Value *NewVal = Src.getScalarVal();
+ llvm::Value *OldVal = Builder.CreateLoad(Ptr, "tmp");
+
+ 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 - 1));
+
+ // 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");
+
+ // Finally, merge the two together and store it.
+ NewVal = Builder.CreateOr(OldVal, NewVal, "tmp");
+
+ Builder.CreateStore(NewVal, Ptr);
+}
+
void CodeGenFunction::EmitStoreThroughOCUComponentLValue(RValue Src, LValue Dst,
QualType Ty) {
// This access turns into a read/modify/write of the vector. Load the input
diff --git a/CodeGen/CodeGenFunction.h b/CodeGen/CodeGenFunction.h
index d56e438df8..dd91a53326 100644
--- a/CodeGen/CodeGenFunction.h
+++ b/CodeGen/CodeGenFunction.h
@@ -401,6 +401,7 @@ public:
/// is 'Ty'.
void EmitStoreThroughLValue(RValue Src, LValue Dst, QualType Ty);
void EmitStoreThroughOCUComponentLValue(RValue Src, LValue Dst, QualType Ty);
+ void EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, QualType Ty);
// Note: only availabe for agg return types
LValue EmitCallExprLValue(const CallExpr *E);
diff --git a/test/CodeGen/bitfield.c b/test/CodeGen/bitfield.c
index 51987655fd..441a54a673 100644
--- a/test/CodeGen/bitfield.c
+++ b/test/CodeGen/bitfield.c
@@ -3,6 +3,8 @@
// RUN: grep "ashr i32 %tmp1, 19" %t1 &&
// RUN: grep "shl i16 %tmp4, 1" %t1 &&
// RUN: grep "lshr i16 %tmp5, 9" %t1
+// RUN: grep "and i32 %tmp, -8192" %t1
+// RUN: grep "and i16 %tmp5, -32513" %t1
// Test bitfield access
@@ -11,3 +13,9 @@ struct STestB1 { int a:13; char b; unsigned short c:7;} stb1;
int f() {
return stb1.a + stb1.b + stb1.c;
}
+
+void g() {
+ stb1.a = -40;
+ stb1.b = 10;
+ stb1.c = 15;
+}