ahatanak created this revision.
ahatanak added reviewers: rjmccall, rsmith.

This patch fixes a bug in r328731 that caused structs with `__weak` fields to 
be passed in registers. This happens when a struct doesn't have a `__weak` 
field but one of its subobjects does. To fix this, I added flag 
CXXRecordDecl::CannotPassInRegisters that propagates outwards and tracks 
whether a `__weak` field was seen. I added a new flag instead of reusing the 
CanPassInRegisters flag since in C++ we cannot always determine the value of a 
class' CanPassInRegisters flag by looking at its subobject's CanPassInRegisters 
flag (CanPassInRegisters=true in the subclass doesn't mean 
CanPassInRegisters=true in the derived class in C++).

rdar://problem/39194693


Repository:
  rC Clang

https://reviews.llvm.org/D45384

Files:
  include/clang/AST/DeclCXX.h
  lib/AST/ASTImporter.cpp
  lib/AST/DeclCXX.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriter.cpp
  test/CodeGenObjCXX/objc-struct-cxx-abi.mm

Index: test/CodeGenObjCXX/objc-struct-cxx-abi.mm
===================================================================
--- test/CodeGenObjCXX/objc-struct-cxx-abi.mm
+++ test/CodeGenObjCXX/objc-struct-cxx-abi.mm
@@ -8,6 +8,8 @@
 // pointer fields are passed directly.
 
 // CHECK: %[[STRUCT_STRONGWEAK:.*]] = type { i8*, i8* }
+// CHECK: %[[STRUCT_CONTAINSSTRONGWEAK:.*]] = type { %[[STRUCT_STRONGWEAK]] }
+// CHECK: %[[STRUCT_DERIVEDSTRONGWEAK:.*]] = type { %[[STRUCT_STRONGWEAK]] }
 // CHECK: %[[STRUCT_STRONG:.*]] = type { i8* }
 // CHECK: %[[STRUCT_S:.*]] = type { i8* }
 // CHECK: %[[STRUCT_CONTAINSNONTRIVIAL:.*]] = type { %{{.*}}, i8* }
@@ -21,6 +23,21 @@
   __weak id fweak;
 };
 
+#ifdef TRIVIALABI
+struct __attribute__((trivial_abi)) ContainsStrongWeak {
+#else
+struct ContainsStrongWeak {
+#endif
+  StrongWeak sw;
+};
+
+#ifdef TRIVIALABI
+struct __attribute__((trivial_abi)) DerivedStrongWeak : StrongWeak {
+#else
+struct DerivedStrongWeak : StrongWeak {
+#endif
+};
+
 #ifdef TRIVIALABI
 struct __attribute__((trivial_abi)) Strong {
 #else
@@ -84,6 +101,18 @@
   return *a;
 }
 
+// CHECK: define void @_Z27testParamContainsStrongWeak18ContainsStrongWeak(%[[STRUCT_CONTAINSSTRONGWEAK]]* %[[A:.*]])
+// CHECK: call %[[STRUCT_CONTAINSSTRONGWEAK]]* @_ZN18ContainsStrongWeakD1Ev(%[[STRUCT_CONTAINSSTRONGWEAK]]* %[[A]])
+
+void testParamContainsStrongWeak(ContainsStrongWeak a) {
+}
+
+// CHECK: define void @_Z26testParamDerivedStrongWeak17DerivedStrongWeak(%[[STRUCT_DERIVEDSTRONGWEAK]]* %[[A:.*]])
+// CHECK: call %[[STRUCT_DERIVEDSTRONGWEAK]]* @_ZN17DerivedStrongWeakD1Ev(%[[STRUCT_DERIVEDSTRONGWEAK]]* %[[A]])
+
+void testParamDerivedStrongWeak(DerivedStrongWeak a) {
+}
+
 // CHECK: define void @_Z15testParamStrong6Strong(i64 %[[A_COERCE:.*]])
 // CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONG]], align 8
 // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[A]], i32 0, i32 0
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -6024,6 +6024,7 @@
   Record->push_back(Data.HasIrrelevantDestructor);
   Record->push_back(Data.HasConstexprNonCopyMoveConstructor);
   Record->push_back(Data.HasDefaultedDefaultConstructor);
+  Record->push_back(Data.CannotPassInRegisters);
   Record->push_back(Data.DefaultedDefaultConstructorIsConstexpr);
   Record->push_back(Data.HasConstexprDefaultConstructor);
   Record->push_back(Data.HasNonLiteralTypeFieldsOrBases);
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -1592,6 +1592,7 @@
   Data.HasIrrelevantDestructor = Record.readInt();
   Data.HasConstexprNonCopyMoveConstructor = Record.readInt();
   Data.HasDefaultedDefaultConstructor = Record.readInt();
+  Data.CannotPassInRegisters = Record.readInt();
   Data.DefaultedDefaultConstructorIsConstexpr = Record.readInt();
   Data.HasConstexprDefaultConstructor = Record.readInt();
   Data.HasNonLiteralTypeFieldsOrBases = Record.readInt();
@@ -1733,6 +1734,7 @@
   MATCH_FIELD(HasIrrelevantDestructor)
   OR_FIELD(HasConstexprNonCopyMoveConstructor)
   OR_FIELD(HasDefaultedDefaultConstructor)
+  MATCH_FIELD(CannotPassInRegisters)
   MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
   OR_FIELD(HasConstexprDefaultConstructor)
   MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -5854,9 +5854,9 @@
   if (RD->isDependentType() || RD->isInvalidDecl())
     return true;
 
-  // The param cannot be passed in registers if CanPassInRegisters is already
-  // set to false.
-  if (!RD->canPassInRegisters())
+  // The param cannot be passed in registers if CannotPassInRegisters is set to
+  // true.
+  if (RD->cannotPassInRegisters())
     return false;
 
   if (CCK != TargetInfo::CCK_MicrosoftX86_64)
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -93,7 +93,7 @@
       DeclaredNonTrivialSpecialMembers(0),
       DeclaredNonTrivialSpecialMembersForCall(0), HasIrrelevantDestructor(true),
       HasConstexprNonCopyMoveConstructor(false),
-      HasDefaultedDefaultConstructor(false),
+      HasDefaultedDefaultConstructor(false), CannotPassInRegisters(false),
       DefaultedDefaultConstructorIsConstexpr(true),
       HasConstexprDefaultConstructor(false),
       HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
@@ -421,6 +421,9 @@
     if (BaseClassDecl->hasVolatileMember())
       setHasVolatileMember(true);
 
+    if (BaseClassDecl->cannotPassInRegisters())
+      setCannotPassInRegisters(true);
+
     // Keep track of the presence of mutable fields.
     if (BaseClassDecl->hasMutableFields()) {
       data().HasMutableFields = true;
@@ -950,7 +953,7 @@
 
         // Structs with __weak fields should never be passed directly.
         if (LT == Qualifiers::OCL_Weak)
-          setCanPassInRegisters(false);
+          setCannotPassInRegisters(true);
 
         Data.HasIrrelevantDestructor = false;
       } else if (!Context.getLangOpts().ObjCAutoRefCount) {
@@ -1117,6 +1120,8 @@
           setHasObjectMember(true);
         if (FieldRec->hasVolatileMember())
           setHasVolatileMember(true);
+        if (FieldRec->cannotPassInRegisters())
+          setCannotPassInRegisters(true);
 
         // C++0x [class]p7:
         //   A standard-layout class is a class that:
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -1108,6 +1108,7 @@
       = FromData.HasConstexprNonCopyMoveConstructor;
     ToData.HasDefaultedDefaultConstructor
       = FromData.HasDefaultedDefaultConstructor;
+    ToData.CannotPassInRegisters = FromData.CannotPassInRegisters;
     ToData.DefaultedDefaultConstructorIsConstexpr
       = FromData.DefaultedDefaultConstructorIsConstexpr;
     ToData.HasConstexprDefaultConstructor
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -479,6 +479,12 @@
     /// constructor.
     unsigned HasDefaultedDefaultConstructor : 1;
 
+    /// Indicates that this class can never be passed or returned in registers.
+    /// This flag is set to true only when this class or one of its subobjects
+    /// has a field (e.g., ObjC __weak pointer field) that makes it impossible
+    /// for this class to be passed in registers.
+    unsigned CannotPassInRegisters : 1;
+
     /// \brief True if a defaulted default constructor for this class would
     /// be constexpr.
     unsigned DefaultedDefaultConstructorIsConstexpr : 1;
@@ -1490,6 +1496,15 @@
     return data().HasIrrelevantDestructor;
   }
 
+  /// Indicates that this class can never be passed or returned in registers.
+  bool cannotPassInRegisters() const {
+    return data().CannotPassInRegisters;
+  }
+
+  void setCannotPassInRegisters(bool CannotPass) {
+    data().CannotPassInRegisters = CannotPass;
+  }
+
   /// \brief Determine whether this class has a non-literal or/ volatile type
   /// non-static data member or base class.
   bool hasNonLiteralTypeFieldsOrBases() const {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to