Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h (revision 173459) +++ include/clang/AST/Decl.h (working copy) @@ -2930,6 +2930,10 @@ /// HasObjectMember - This is true if this struct has at least one member /// containing an Objective-C object pointer type. bool HasObjectMember : 1; + + /// HasVolatileMember - This is true if struct has at least one member of + /// 'volatile' type. + bool HasVolatileMember : 1; /// \brief Whether the field declarations of this record have been loaded /// from external storage. To avoid unnecessary deserialization of @@ -2986,6 +2990,9 @@ bool hasObjectMember() const { return HasObjectMember; } void setHasObjectMember (bool val) { HasObjectMember = val; } + bool hasVolatileMember() const { return HasVolatileMember; } + void setHasVolatileMember (bool val) { HasVolatileMember = val; } + /// \brief Determines whether this declaration represents the /// injected class name. /// Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp (revision 173459) +++ lib/AST/Decl.cpp (working copy) @@ -2734,6 +2734,7 @@ HasFlexibleArrayMember = false; AnonymousStructOrUnion = false; HasObjectMember = false; + HasVolatileMember = false; LoadedFieldsFromExternalStorage = false; assert(classof(static_cast(this)) && "Invalid Kind!"); } Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp (revision 173459) +++ lib/AST/DeclCXX.cpp (working copy) @@ -301,6 +301,9 @@ // has an Objective-C object member. if (BaseClassDecl->hasObjectMember()) setHasObjectMember(true); + + if (BaseClassDecl->hasVolatileMember()) + setHasVolatileMember(true); // Keep track of the presence of mutable fields. if (BaseClassDecl->hasMutableFields()) @@ -751,6 +754,8 @@ data().HasIrrelevantDestructor = false; if (FieldRec->hasObjectMember()) setHasObjectMember(true); + if (FieldRec->hasVolatileMember()) + setHasVolatileMember(true); // C++0x [class]p7: // A standard-layout class is a class that: Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp (revision 173459) +++ lib/CodeGen/CGExprAgg.cpp (working copy) @@ -792,6 +792,11 @@ AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed, needsGC(E->getLHS()->getType()), AggValueSlot::IsAliased); + // A non-volatile aggregate destination might have volatile member. + if (!LHSSlot.isVolatile() && + CGF.IsAggrVolatile(E->getLHS()->getType())) + LHSSlot.setVolatile(true); + CGF.EmitAggExpr(E->getRHS(), LHSSlot); // Copy into the destination if the assignment isn't ignored. Index: lib/CodeGen/CGValue.h =================================================================== --- lib/CodeGen/CGValue.h (revision 173459) +++ lib/CodeGen/CGValue.h (working copy) @@ -412,6 +412,10 @@ return Quals.hasVolatile(); } + void setVolatile(bool flag) { + Quals.setVolatile(flag); + } + Qualifiers::ObjCLifetime getObjCLifetime() const { return Quals.getObjCLifetime(); } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h (revision 173459) +++ lib/CodeGen/CodeGenFunction.h (working copy) @@ -1665,14 +1665,23 @@ void EmitExprAsInit(const Expr *init, const ValueDecl *D, LValue lvalue, bool capturedByInit); + /// IsAggrVolatile - returns true if aggregate type has a volatile + /// member. + bool IsAggrVolatile(QualType T) { + if (const RecordType *RT = T->getAs()) + if (const RecordDecl *RD = cast(RT->getDecl())) + return RD->hasVolatileMember(); + return false; + } /// EmitAggregateCopy - Emit an aggrate assignment. /// /// The difference to EmitAggregateCopy is that tail padding is not copied. /// This is required for correctness when assigning non-POD structures in C++. void EmitAggregateAssign(llvm::Value *DestPtr, llvm::Value *SrcPtr, - QualType EltTy, bool isVolatile=false, - CharUnits Alignment = CharUnits::Zero()) { - EmitAggregateCopy(DestPtr, SrcPtr, EltTy, isVolatile, Alignment, true); + QualType EltTy) { + bool IsVolatile = IsAggrVolatile(EltTy); + EmitAggregateCopy(DestPtr, SrcPtr, EltTy, IsVolatile, CharUnits::Zero(), + true); } /// EmitAggregateCopy - Emit an aggrate copy. Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp (revision 173459) +++ lib/Sema/SemaDecl.cpp (working copy) @@ -10462,6 +10462,8 @@ } if (Record && FDTTy->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); + if (Record && FDTTy->getDecl()->hasVolatileMember()) + Record->setHasVolatileMember(true); } else if (FDTy->isObjCObjectType()) { /// A field cannot be an Objective-c object Diag(FD->getLocation(), diag::err_statically_allocated_object) @@ -10508,6 +10510,8 @@ } } } + if (Record && FD->getType().isVolatileQualified()) + Record->setHasVolatileMember(true); // Keep track of the number of named members. if (FD->getIdentifier()) ++NumNamedMembers; Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp (revision 173459) +++ lib/Serialization/ASTReaderDecl.cpp (working copy) @@ -475,6 +475,7 @@ RD->setHasFlexibleArrayMember(Record[Idx++]); RD->setAnonymousStructOrUnion(Record[Idx++]); RD->setHasObjectMember(Record[Idx++]); + RD->setHasVolatileMember(Record[Idx++]); } void ASTDeclReader::VisitValueDecl(ValueDecl *VD) { Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp (revision 173459) +++ lib/Serialization/ASTWriterDecl.cpp (working copy) @@ -263,6 +263,7 @@ Record.push_back(D->hasFlexibleArrayMember()); Record.push_back(D->isAnonymousStructOrUnion()); Record.push_back(D->hasObjectMember()); + Record.push_back(D->hasVolatileMember()); if (!D->hasAttrs() && !D->isImplicit() && @@ -1456,6 +1457,7 @@ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasObjectMember + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasVolatileMember // DC Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset Index: test/CodeGen/no-opt-volatile-memcpy.c =================================================================== --- test/CodeGen/no-opt-volatile-memcpy.c (revision 0) +++ test/CodeGen/no-opt-volatile-memcpy.c (working copy) @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -O -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s +// rdar://11861085 + +struct s { + char filler [128]; + volatile int x; +}; + +struct s gs; + +void foo (void) { + struct s ls; + ls = ls; + gs = gs; + ls = gs; +} +// CHECK: call void @llvm.memcpy +// CHECK: call void @llvm.memcpy +// CHECK: call void @llvm.memcpy + +struct s1 { + struct s y; +}; + +struct s1 s; + +void fee (void) { + s = s; + s.y = gs; +} +// CHECK: call void @llvm.memcpy +// CHECK: call void @llvm.memcpy Index: test/CodeGenCXX/no-opt-volatile-memcpy.cpp =================================================================== --- test/CodeGenCXX/no-opt-volatile-memcpy.cpp (revision 0) +++ test/CodeGenCXX/no-opt-volatile-memcpy.cpp (working copy) @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -O -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s +// rdar://11861085 + +struct s { + char filler [128]; + volatile int x; +}; + +struct s gs; + +void foo (void) { + struct s ls; + ls = ls; + gs = gs; + ls = gs; +} +// CHECK: call void @llvm.memcpy +// CHECK: call void @llvm.memcpy +// CHECK: call void @llvm.memcpy + +struct s1 { + struct s y; +}; + +struct s1 s; + +void fee (void) { + s = s; + s.y = gs; +} +// CHECK: call void @llvm.memcpy +// CHECK: call void @llvm.memcpy + + +struct d : s1 { +}; + +d gd; + +void gorf(void) { + gd = gd; +} +// CHECK: call void @llvm.memcpy +