Index: include/clang/AST/DeclCXX.h =================================================================== --- include/clang/AST/DeclCXX.h +++ include/clang/AST/DeclCXX.h @@ -357,14 +357,6 @@ /// \brief True when there are private non-static data members. bool HasPublicFields : 1; - /// \brief True is this class has already been checked as candidate - /// for writeonce semantics. - bool IsWriteOnceChecked : 1; - - /// \brief True if instances of this class are candidates - /// for writeonce semantics. - bool IsWriteOnceCandidate : 1; - /// \brief True if this class (or any subobject) has mutable fields. bool HasMutableFields : 1; @@ -774,8 +766,6 @@ return method_iterator(decls_end()); } - bool computeWriteOnceCandidacy() const; - /// Iterator access to constructor members. typedef specific_decl_iterator ctor_iterator; typedef llvm::iterator_range> Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -58,8 +58,6 @@ HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), - IsWriteOnceChecked(false), - IsWriteOnceCandidate(false), HasMutableFields(false), HasVariantMembers(false), HasOnlyCMembers(true), @@ -1350,73 +1348,6 @@ return false; } -/// \brief A class is a candidate for 'writeonce' semantics if -/// none of its methods writes to memory. -bool CXXRecordDecl::computeWriteOnceCandidacy() const { - // The class must be defined and concrete. - if (!isCompleteDefinition() || isDependentType()) return false; - - // If this has already been checked, then return the stored value. - if (data().IsWriteOnceChecked) return data().IsWriteOnceCandidate; - - // Otherwise, mark that this is checked. - data().IsWriteOnceChecked = true; - assert(!data().IsWriteOnceCandidate && - "The candidacy should not have been set yet."); - - // Check each method, excluding constructors and destructors. - // NOTE: The invariant intrinsic calls are generated right after the - // construction of a given const object (which must be initialized) - // and right before its destruction at the end of its lifetime. - // Both constructors and destructors modify the allocated memory and - // and will not be called in the middle of an invariant_start/end - // pair, thus may not affect the reduction of loads. So, it does not - // help to handle constructors here as well. - for (auto *M : methods()) { - if (isa(M) || isa(M)) continue; - - // If we already know that this method does not write to memory, skip it. - // NOTE: CodeGenModule::ConstructAttributeList() marks declarations with - // ConstAttr and PureAttr attributes, respectively, as 'readnone' and - // 'readonly' (for LLVM). - if (M->hasAttr() || M->hasAttr()) continue; - - const FunctionDecl *Def = nullptr; - bool IsDefined = M->isDefined(Def); - - // If this is not defined and not virtual, then it may write to memory. - // So it's not a candidate for 'writeonce' semantics. - // If it is purely virtual then it must be overriden and its overriding - // method (in this context) must be a candidate for 'writeonce' semantics. - // Skip it. - if (!IsDefined) { - if (M->isPure()) { - assert(M->isVirtual() && "Not defined and pure implies virtual."); - continue; - } - return false; - } - - // If this is trivial, skip it. - if (Def->hasTrivialBody()) continue; - - // TODO: Any other case? - } - - // Check bases - for (const auto &I : bases()) { - const RecordType *Ty = I.getType()->getAs(); - assert(Ty && "No type?"); - CXXRecordDecl *Base = - cast_or_null(Ty->getDecl()->getDefinition()); - - if (!Base || !Base->computeWriteOnceCandidacy()) return false; - } - - data().IsWriteOnceCandidate = true; - return true; -} - void CXXRecordDecl::completeDefinition() { completeDefinition(nullptr); } Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -1937,15 +1937,8 @@ } bool QualType::isWriteOnce(ASTContext &Context) { - // TODO: Include C objects as well? - if (Context.getLangOpts().CPlusPlus && isConstant(Context) && - !getTypePtr()->isReferenceType()) { - if (const CXXRecordDecl *Record = - Context.getBaseElementType(*this)->getAsCXXRecordDecl()) - return Record->computeWriteOnceCandidacy(); - return true; - } - return false; + return (Context.getLangOpts().CPlusPlus && isConstant(Context) && + !getTypePtr()->isReferenceType()); } bool QualType::isPODType(ASTContext &Context) const { Index: test/CodeGenCXX/const-invariant.cpp =================================================================== --- test/CodeGenCXX/const-invariant.cpp +++ test/CodeGenCXX/const-invariant.cpp @@ -167,11 +167,11 @@ // 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 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 {{.*}}@llvm.invariant.start(i64 {{[0-9]+}}, i8* bitcast ({{.*}} @_ZL3i_f to i8*)) // CHECK-NL-CO-OBJ: call void @_ZN1IC{{[0-9]+}}Ei({{.*}}* @_ZL3i_i, {{.*}}) // CHECK-NL-CO-OBJ: call {{.*}}@llvm.invariant.start(i64 {{[0-9]+}}, i8* bitcast ({{.*}} @_ZL3i_i to i8*)) // CHECK-NL-CO-OBJ: call void @_ZN2IVC{{[0-9]+}}Ei({{.*}}* @_ZL4i_iv, {{.*}}) -// CHECK-NL-CO-OBJ-NOT: call {{.*}}@llvm.invariant.start(i64 {{[0-9]+}}, i8* bitcast ({{.*}} @_ZL4i_iv to i8*)) +// CHECK-NL-CO-OBJ: call {{.*}}@llvm.invariant.start(i64 {{[0-9]+}}, i8* bitcast ({{.*}} @_ZL4i_iv to i8*)) // CHECK-NL-CO-OBJ: call void @_ZN3CIVC{{[0-9]+}}Ei({{.*}}* @_ZL5i_civ, {{.*}}) // CHECK-NL-CO-OBJ: call {{.*}}@llvm.invariant.start(i64 {{[0-9]+}}, i8* bitcast ({{.*}} @_ZL5i_civ to i8*)) @@ -303,11 +303,11 @@ // CHECK-L-CO-OBJ: %i_f = alloca {{.*}} // CHECK-L-CO-OBJ: call void @_ZN1FC{{[0-9]+}}Ei({{.*}}* %i_f, - // CHECK-L-CO-OBJ-NOT: call {{.*}}@llvm.invariant.start( + // CHECK-L-CO-OBJ: call {{.*}}@llvm.invariant.start( bar_f(i_f); foo_f(&i_f); // May change i_f. bar_f(i_f); - // CHECK-L-CO-OBJ-NOT: call {{.*}}@llvm.invariant.end( + // CHECK-L-CO-OBJ: call {{.*}}@llvm.invariant.end( } // Example 1 with type inheriting non-virtual base: @@ -337,11 +337,11 @@ // CHECK-L-CO-OBJ: %i_iv = alloca {{.*}} // CHECK-L-CO-OBJ: call void @_ZN2IVC{{[0-9]+}}Ei({{.*}}* %i_iv, - // CHECK-L-CO-OBJ-NOT: call {{.*}}@llvm.invariant.start( + // CHECK-L-CO-OBJ: call {{.*}}@llvm.invariant.start( bar_iv(i_iv); foo_iv(&i_iv); // Does not change i_iv. bar_iv(i_iv); - // CHECK-L-CO-OBJ-NOT: call {{.*}}@llvm.invariant.end( + // CHECK-L-CO-OBJ: call {{.*}}@llvm.invariant.end( } // Example 1 with type inheriting virtual writeonce base: