[clang] [ObjC] Check entire chain of superclasses to see if class has fixed offsets (PR #81335)

via cfe-commits cfe-commits at lists.llvm.org
Sat Feb 10 15:30:57 PST 2024


https://github.com/AtariDreams updated https://github.com/llvm/llvm-project/pull/81335

>From 527e24ae4d6f662c2bee1a281914df028bcd01e1 Mon Sep 17 00:00:00 2001
From: Rose <83477269+AtariDreams at users.noreply.github.com>
Date: Fri, 9 Feb 2024 17:51:15 -0500
Subject: [PATCH 1/2] [ObjC] Add pre-commit tests [NFC]

---
 .../constant-non-fragile-ivar-offset.m        | 84 +++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m b/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
index 788b3220af3067..bed6497f8827ae 100644
--- a/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
+++ b/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
@@ -1,6 +1,13 @@
 // RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -emit-llvm %s -o - | FileCheck %s
 
 // CHECK: @"OBJC_IVAR_$_StaticLayout.static_layout_ivar" = hidden constant i64 20
+// CHECK: @"OBJC_IVAR_$_StaticLayoutSubClass.static_layout_ivar2" = hidden constant i64 24
+// CHECK: @"OBJC_IVAR_$_MyClass.myIvar" = constant i64 20
+// CHECK: @"OBJC_IVAR_$_MyClass._myProperty" = hidden constant i64 24
+// CHECK: @"OBJC_IVAR_$_AnotherClass.privateId" = constant i64 24
+// CHECK: @"OBJC_IVAR_$_AnotherClass.anotherPrivateId" = hidden constant i64 32
+// CHECK: @"OBJC_IVAR_$_SuperClass.superClassIvar" = constant i64 20
+// CHECK: @"OBJC_IVAR_$_SubClass.subClassIvar" = global i64 24
 // CHECK: @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar" = hidden global i64 12
 
 @interface NSObject {
@@ -20,6 +27,83 @@ -(void)meth {
 }
 @end
 
+// Scenario 1: Ivars declared in the @interface
+ at interface MyClass : NSObject
+{
+    int myIvar; // Declare an ivar
+}
+
+ at property (nonatomic, assign) int myProperty; // Synthesize a property
+
+ at end
+
+ at implementation MyClass 
+
+- (void)exampleMethod {
+    self.myProperty = 42; // Access the property
+    myIvar = 10; // Access the ivar directly
+}
+
+ at end
+
+// Scenario 2: Ivars declared directly in the @implementation
+ at interface AnotherClass : NSObject
+{
+  id privateId;
+}
+
+ at end
+
+ at implementation AnotherClass
+{
+    id anotherPrivateId; // Declare an ivar directly in the implementation
+}
+
+- (void)doSomething {
+   privateId = anotherPrivateId;
+}
+
+ at end
+
+// Scenario 3: Inheritance and Ivars
+ at interface SuperClass : NSObject
+{
+    int superClassIvar;
+}
+ at end
+
+ at implementation SuperClass
+ at end
+
+ at interface SubClass : SuperClass
+{
+    double subClassIvar;
+}
+ at end
+
+ at implementation SubClass
+- (void)exampleMethod {
+    // CHECK: load i64, ptr @"OBJC_IVAR_$SuperClass
+    superClassIvar = 100; // Access superclass ivar
+    subClassIvar = 3.14; // Access subclass ivar
+}
+ at end
+
+// Scenario 4: Custom Getter/Setter Methods
+ at interface CustomPropertyClass : NSObject
+ at property (nonatomic, strong, getter=myCustomGetter, setter=myCustomSetter:) id customProperty;
+ at end
+
+ at implementation CustomPropertyClass
+- (id) myCustomGetter {
+    return 0;
+}
+
+- (void)myCustomSetter:(id)newValue {
+    // Custom setter logic
+}
+ at end
+
 @interface NotNSObject {
   int these, might, change;
 }

>From f22d935cb80d79ea5354317bcd34049579ccf3ee Mon Sep 17 00:00:00 2001
From: Rose <83477269+AtariDreams at users.noreply.github.com>
Date: Fri, 9 Feb 2024 17:47:59 -0500
Subject: [PATCH 2/2] [ObjC] Check entire chain of superclasses to see if class
 has fixed offsets

As of now, we only check if a class directly inherits from NSObject to determine if said lass has fixed offsets and can therefore "opt-out" from the non-fragile ABI for ivars.

However, if an NSObject subclass has fixed offsets, then so must the subclasses of that subclass, so this allows us to optimize instances of subclasses of subclasses that inherit from NSObject and so on.

Fixes: #81369
---
 clang/lib/CodeGen/CGObjCMac.cpp               | 22 ++++++++++++++-----
 .../constant-non-fragile-ivar-offset.m        |  6 ++---
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index 27d77e9a8a5511..ceee70a5d79b3e 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -1593,12 +1593,22 @@ class CGObjCNonFragileABIMac : public CGObjCCommonMac {
   }
 
   bool isClassLayoutKnownStatically(const ObjCInterfaceDecl *ID) {
-    // NSObject is a fixed size. If we can see the @implementation of a class
-    // which inherits from NSObject then we know that all it's offsets also must
-    // be fixed. FIXME: Can we do this if see a chain of super classes with
-    // implementations leading to NSObject?
-    return ID->getImplementation() && ID->getSuperClass() &&
-           ID->getSuperClass()->getName() == "NSObject";
+    // Test a class by checking its superclasses up to its base class if it has
+    // one
+    while (ID) {
+      // The base class NSObject is a fixed size
+      if (ID->getName() == "NSObject")
+        return true;
+
+      // If we cannot see the @implementation of a class, we cannot assume fixed
+      // offsets
+      if (!ID->getImplementation())
+        return false;
+
+      // Test superclass
+      ID = ID->getSuperClass();
+    }
+    return false;
   }
 
 public:
diff --git a/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m b/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
index bed6497f8827ae..960f8768fb6ab6 100644
--- a/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
+++ b/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
@@ -7,8 +7,8 @@
 // CHECK: @"OBJC_IVAR_$_AnotherClass.privateId" = constant i64 24
 // CHECK: @"OBJC_IVAR_$_AnotherClass.anotherPrivateId" = hidden constant i64 32
 // CHECK: @"OBJC_IVAR_$_SuperClass.superClassIvar" = constant i64 20
-// CHECK: @"OBJC_IVAR_$_SubClass.subClassIvar" = global i64 24
-// CHECK: @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar" = hidden global i64 12
+// CHECK: @"OBJC_IVAR_$_SubClass.subClassIvar" = constant i64 24
+// CHECK: @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar" = hidden constant i64 12
 
 @interface NSObject {
   int these, will, never, change, ever;
@@ -83,7 +83,7 @@ @interface SubClass : SuperClass
 
 @implementation SubClass
 - (void)exampleMethod {
-    // CHECK: load i64, ptr @"OBJC_IVAR_$SuperClass
+    // CHECK-NOT: load i64, ptr @"OBJC_IVAR_$SuperClass
     superClassIvar = 100; // Access superclass ivar
     subClassIvar = 3.14; // Access subclass ivar
 }



More information about the cfe-commits mailing list