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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits