lvoufo created this revision.
lvoufo added reviewers: dberlin, chandlerc, nlewycky, majnemer.
lvoufo added a subscriber: cfe-commits.

Adapting solution from const members of non-const objects (D13618)....

http://reviews.llvm.org/D14418

Files:
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCXX/const-invariant.cpp

Index: test/CodeGenCXX/const-invariant.cpp
===================================================================
--- test/CodeGenCXX/const-invariant.cpp
+++ test/CodeGenCXX/const-invariant.cpp
@@ -165,7 +165,7 @@
 // CHECK-NL-CO-OBJ: call void @_ZN1DC{{[0-9]+}}Ei({{.*}}* @_ZL3i_d, {{.*}})
 // CHECK-NL-CO-OBJ: call {{.*}}@llvm.invariant.start(i64 {{[0-9]+}}, i8* bitcast ({{.*}} @_ZL3i_d to i8*))
 // CHECK-NL-CO-OBJ: call void @_ZN1MC{{[0-9]+}}Ei({{.*}}* @_ZL3i_m, {{.*}})
-// CHECK-NL-CO-OBJ: call {{.*}}@llvm.invariant.start(i64 {{[0-9]+}}, i8* bitcast ({{.*}} @_ZL3i_m to i8*))
+// CHECK-NL-CO-OBJ: call {{.*}}@llvm.invariant.start(i64 {{[0-9]+}}, i8* bitcast ({{.*}} @_ZL3i_m to i8*),
 // CHECK-NL-CO-OBJ: call void @_ZN1FC{{[0-9]+}}Ei({{.*}}* @_ZL3i_f, {{.*}})
 // CHECK-NL-CO-OBJ-NOT: call {{.*}}@llvm.invariant.start(i64 {{[0-9]+}}, i8* bitcast ({{.*}} @_ZL3i_f to i8*))
 // CHECK-NL-CO-OBJ: call void @_ZN1IC{{[0-9]+}}Ei({{.*}}* @_ZL3i_i, {{.*}})
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1929,12 +1929,20 @@
     OffsetsInfoType() : Computed(false) { }
   };
 
-  /// \brief A collection of invariant offsets per given record.
+  /// \brief A collection of invariant offsets per given record,
+  /// for non-const objects.
   llvm::DenseMap<const CXXRecordDecl *, OffsetsInfoType> InvariantOffsets;
 
+  /// \brief A collection of non-mutable offsets per given record,
+  /// for const objects.
+  llvm::DenseMap<const CXXRecordDecl *, OffsetsInfoType> NonMutableOffsets;
+
   /// \brief Compute the invariant offsets of a given Record.
   OffsetsType& ComputeInvariantOffsets(const CXXRecordDecl *Record);
 
+  /// \brief Compute the non-mutable offsets of a given Record.
+  OffsetsType& ComputeNonMutableOffsets(const CXXRecordDecl *Record);
+
 public:
   InvariantArgs EmitInvariantStart(const VarDecl &D, llvm::Value *Addr,
                                    bool IsGlobalConstant = true);
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -927,6 +927,8 @@
   C->setDoesNotThrow();
 }
 
+/// This assumes that the fields of the given Record are assumed to be
+/// non-writeonce by default.
 CodeGenFunction::OffsetsType&
 CodeGenFunction::ComputeInvariantOffsets(const CXXRecordDecl *Record) {
   ASTContext &Ctx = getContext();
@@ -951,11 +953,69 @@
 
       uint64_t Offset = Ctx.getFieldOffset(Field);
       Args.push_back(llvm::ConstantInt::get(Int64Ty, Offset));  // Offset
+
+      // If this writeonce type happens to be a record holding mutable
+      // fields, make sure to collect the offsets.
+      if (const CXXRecordDecl *RecField =
+          Ctx.getBaseElementType(FieldType)->getAsCXXRecordDecl()) {
+        if (RecField->hasMutableFields()) {
+          auto &FieldArgs = ComputeNonMutableOffsets(RecField);
+          Args.insert(Args.end(), FieldArgs.begin(), FieldArgs.end());
+        }
+      }
     } else if (const CXXRecordDecl *RecField =
                Ctx.getBaseElementType(FieldType)->getAsCXXRecordDecl()) {
       auto &FieldArgs = ComputeInvariantOffsets(RecField);
       Args.insert(Args.end(), FieldArgs.begin(), FieldArgs.end());
     }
+
+    // Ignore non-writeonce non-record fields.
+  }
+
+  return Args;
+}
+
+/// This is similar to ComputeInvariantOffsets() but collect offsets of
+/// non-mutable fields instead of those of writeonce fields.
+/// It is meant to be used when the given Record is writeonce and its
+/// fields are assumed to be writeonce by default.
+CodeGenFunction::OffsetsType&
+CodeGenFunction::ComputeNonMutableOffsets(const CXXRecordDecl *Record) {
+  ASTContext &Ctx = getContext();
+  auto &OffsetsInfo = NonMutableOffsets.FindAndConstruct(Record).second;
+  OffsetsType &Args = OffsetsInfo.Offsets;
+
+  // If this has already been computed, then return the stored value.
+  if (OffsetsInfo.Computed) return Args;
+
+  // Otherwise, mark that this is computed.
+  OffsetsInfo.Computed = true;
+  assert(Args.empty() && "There should be no offset specified yet.");
+
+  // Trace through fields collecting offsets of writeonce candidates.
+  for (const auto *Field : Record->fields()) {
+    assert(dyn_cast<FieldDecl>(Field) && "Field decls only.");
+    QualType FieldType = Field->getType();
+
+    if (Field->isMutable()) {
+      // Ignore mutable fields.
+      continue;
+    } else if (const CXXRecordDecl *RecField =
+               Ctx.getBaseElementType(FieldType)->getAsCXXRecordDecl()) {
+      if (RecField->hasMutableFields()) {
+        auto &FieldArgs = ComputeNonMutableOffsets(RecField);
+        Args.insert(Args.end(), FieldArgs.begin(), FieldArgs.end());
+        continue;
+      }
+    }
+
+    // This field is writeonce.
+    CharUnits WidthChars = Ctx.getTypeSizeInChars(FieldType);
+    uint64_t Width = WidthChars.getQuantity();
+    Args.push_back(llvm::ConstantInt::get(Int64Ty, Width));  // Size
+
+    uint64_t Offset = Ctx.getFieldOffset(Field);
+    Args.push_back(llvm::ConstantInt::get(Int64Ty, Offset));  // Offset
   }
 
   return Args;
@@ -985,8 +1045,16 @@
   } else if (Ty.isWriteOnce(Ctx)) {
     Args.Size = llvm::ConstantInt::get(Int64Ty, Width);
     Args.Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
+
+    // If this writeonce type happens to be a record holding mutable
+    // fields, make sure to collect the offsets.
+    if (const CXXRecordDecl *Record =
+        Ctx.getBaseElementType(Ty)->getAsCXXRecordDecl()) {
+      if (Record->hasMutableFields())
+        Offsets = ComputeNonMutableOffsets(Record);
+    }
   } else if (const CXXRecordDecl *Record =
-              Ctx.getBaseElementType(Ty)->getAsCXXRecordDecl()) {
+             Ctx.getBaseElementType(Ty)->getAsCXXRecordDecl()) {
     Offsets = ComputeInvariantOffsets(Record);
     // If there are invariant offsets in this non-writeonce record,
     // then emit the intrinsic call with the offsets. Otherwise,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to