From: Lauro Ramos Venancio Date: Tue, 22 Jan 2008 22:36:45 +0000 (+0000) Subject: Implement bitfield write. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a0c5d0eacede0f67ce46707263ddf4d8de0df706;p=clang Implement bitfield write. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46258 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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(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; +}