Fix redundant load of bit-fields on assignment (to get the updated
value).
 - Use extra argument to EmitStoreThroughLValue to provide place to
   write update bit-field value if caller requires it.
 - This fixes several FIXMEs.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59615 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 95733ab..9328a53 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -392,7 +392,8 @@
 }
 
 void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
-                                                     QualType Ty) {
+                                                     QualType Ty, 
+                                                     llvm::Value **Result) {
   unsigned StartBit = Dst.getBitfieldStartBit();
   unsigned BitfieldSize = Dst.getBitfieldSize();
   llvm::Value *Ptr = Dst.getBitfieldAddr();
@@ -403,12 +404,31 @@
 
   // 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::Value *SrcVal = Src.getScalarVal();
+  llvm::Value *NewVal = Builder.CreateIntCast(SrcVal, EltTy, false, "tmp");
   llvm::Constant *Mask = 
     llvm::ConstantInt::get(llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize));
   NewVal = Builder.CreateAnd(NewVal, Mask, "bf.value");
 
+  // Return the new value of the bit-field, if requested.
+  if (Result) {
+    // Cast back to the proper type for result.
+    const llvm::Type *SrcTy = SrcVal->getType();
+    llvm::Value *SrcTrunc = Builder.CreateIntCast(NewVal, SrcTy, false,
+                                                  "bf.reload.val");
+
+    // Sign extend if necessary.
+    if (Dst.isBitfieldSigned()) {
+      unsigned SrcTySize = CGM.getTargetData().getTypeSizeInBits(SrcTy);
+      llvm::Value *ExtraBits = llvm::ConstantInt::get(SrcTy,
+                                                      SrcTySize - BitfieldSize);
+      SrcTrunc = Builder.CreateAShr(Builder.CreateShl(SrcTrunc, ExtraBits), 
+                                    ExtraBits, "bf.reload.sext");
+    }
+
+    *Result = SrcTrunc;
+  }
+
   // 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.
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index d87edc3..b236a6a 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -786,15 +786,14 @@
   // Convert the result back to the LHS type.
   Result = EmitScalarConversion(Result, ResultTy, LHSTy);
   
-  // Store the result value into the LHS lvalue.
-  CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy);
-
-  // For bitfields, we need the value in the bitfield. Note that
-  // property references do not reload their value (even though the
-  // setter may have changed it).
-  // FIXME: This adds an extra bitfield load
+  // Store the result value into the LHS lvalue. Bit-fields are
+  // handled specially because the result is altered by the store.
   if (LHSLV.isBitfield())
-    Result = EmitLoadOfLValue(LHSLV, LHSTy);
+    CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy,
+                                       &Result);
+  else
+    CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy);
+  
   return Result;
 }
 
@@ -1003,16 +1002,14 @@
   LValue LHS = EmitLValue(E->getLHS());
   Value *RHS = Visit(E->getRHS());
   
-  // Store the value into the LHS.
+  // Store the value into the LHS.  Bit-fields are handled specially
+  // because the result is altered by the store.
   // FIXME: Volatility!
-  CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
-
-  // For bitfields, we need the value in the bitfield. Note that
-  // property references do not reload their value (even though the
-  // setter may have changed it).
-  // FIXME: This adds an extra bitfield load
   if (LHS.isBitfield())
-    return EmitLoadOfLValue(LHS, E->getLHS()->getType());
+    CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
+                                       &RHS);
+  else
+    CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
 
   // Return the RHS.
   return RHS;
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 5d99dba..05b2793 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -32,6 +32,7 @@
   class BasicBlock;
   class Module;
   class SwitchInst;
+  class Value;
 }
 
 namespace clang {
@@ -446,8 +447,16 @@
   void EmitStoreThroughLValue(RValue Src, LValue Dst, QualType Ty);
   void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst,
                                                 QualType Ty);
-  void EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, QualType Ty);
   void EmitStoreThroughPropertyRefLValue(RValue Src, LValue Dst, QualType Ty);
+
+  /// EmitStoreThroughLValue - Store Src into Dst with same
+  /// constraints as EmitStoreThroughLValue. 
+  ///
+  /// \param Result [out] - If non-null, this will be set to a Value*
+  /// for the bit-field contents after the store, appropriate for use
+  /// as the result of an assignment to the bit-field.
+  void EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, QualType Ty,
+                                      llvm::Value **Result=0);
    
   // Note: only availabe for agg return types
   LValue EmitBinaryOperatorLValue(const BinaryOperator *E);
diff --git a/lib/CodeGen/README.txt b/lib/CodeGen/README.txt
index 33fbfdb..12a08e1 100644
--- a/lib/CodeGen/README.txt
+++ b/lib/CodeGen/README.txt
@@ -17,8 +17,3 @@
 directly.
 
 //===---------------------------------------------------------------------===//
-
-Bitfields should not reload the stored value just to return the
-correct result.
-
-//===---------------------------------------------------------------------===//