]> granicus.if.org Git - clang/commitdiff
Implement bitfield write.
authorLauro Ramos Venancio <lauro.venancio@gmail.com>
Tue, 22 Jan 2008 22:36:45 +0000 (22:36 +0000)
committerLauro Ramos Venancio <lauro.venancio@gmail.com>
Tue, 22 Jan 2008 22:36:45 +0000 (22:36 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46258 91177308-0d34-0410-b5e6-96231b3b80d8

CodeGen/CGExpr.cpp
CodeGen/CodeGenFunction.h
test/CodeGen/bitfield.c

index 9e907216ee2822fef539721f0b07dde7f061efa4..9abf1a4271081a98b6a40270f0f661e92e559d42 100644 (file)
@@ -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
index d56e438df82c1572f9519660d277dc6fc6d2455c..dd91a533260f064308cb6beb9583f3ab7e55c82b 100644 (file)
@@ -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);
index 51987655fd0509821206b839f2c1f014c609656e..441a54a6732891b4fa332ca1302a7df6d775d28b 100644 (file)
@@ -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;
+}