[prev in list] [next in list] [prev in thread] [next in thread] 

List:       cfe-commits
Subject:    Re: ObjFW runtime: Add objc_msg_lookup(_super)_{fp,st}ret
From:       Jonathan Schleifer <js () webkeks ! org>
Date:       2013-07-20 14:49:46
Message-ID: 444F4143-873B-4146-9C80-B47B9810DEE2 () webkeks ! org
[Download RAW message or body]

Am 19.07.2013 um 20:17 schrieb Eli Friedman:

> That's the place where every single other __has_feature is documented.
> I mean, if it's important enough to add a __has_feature name for it,
> it's surely important enough to document the feature in question.

Ok, I added it to that list in the attached patch. It didn't seem =
significant enough for me to add it there, but if you say so ;).

Please review the patch and import it if it is fine.

--
Jonathan

["0001-Issue-calls-to-objc_msg_lookup_stret-for-the-ObjFW-r.patch" (0001-Issue-calls-to-objc_msg_lookup_stret-for-the-ObjFW-r.patch)]

From 6da31690b38ea70cc3d4eb936814afc1843cffb2 Mon Sep 17 00:00:00 2001
From: Jonathan Schleifer <js@webkeks.org>
Date: Sun, 7 Apr 2013 14:58:39 +0200
Subject: [PATCH] Issue calls to objc_msg_lookup_stret for the ObjFW runtime.

While this might seem pointless at first, it makes it possible to
correctly handle forwarding by calling the appropriate forwarding
function.
---
 docs/LanguageExtensions.rst     |   17 +++++++++++++
 lib/CodeGen/CGObjCGNU.cpp       |   51 +++++++++++++++++++++++++++++----------
 lib/Lex/PPMacroExpansion.cpp    |    1 +
 test/CodeGenObjC/stret_lookup.m |   29 ++++++++++++++++++++++
 4 files changed, 85 insertions(+), 13 deletions(-)
 create mode 100644 test/CodeGenObjC/stret_lookup.m

diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index bfc5feb..e1b008d 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -1257,6 +1257,23 @@ Further examples of these attributes are available in the \
static analyzer's `lis  Query for these features with \
``__has_attribute(ns_consumed)``,  ``__has_attribute(ns_returns_retained)``, etc.
 
+objc_msg_lookup_stret
+---------------------
+
+Traditionally, if a runtime is used that follows the GNU Objective-C ABI, a
+call to objc_msg_lookup() would be emitted for each message send, which would
+return a pointer to the actual implementation of the method. However,
+objc_msg_lookup() has no information at all about the method signature of the
+actual method. Therefore, certain features like forwarding messages cannot be
+correctly implemented for methods returning structs using objc_msg_lookup(), as
+methods returning structs use a slightly different calling convention.
+
+To work around this, Clang emits calls to objc_msg_lookup_stret() instead for
+methods that return structs if the runtime supports this, allowing the runtime
+to use a different forwarding handler for methods returning structs.
+
+To check if Clang emits calls to objc_msg_lookup_stret(),
+__has_feature(objc_msg_lookup_stret) can be used.
 
 Function Overloading in C
 =========================
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index fbf8a1a..2a99df4 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -454,13 +454,15 @@ protected:
   virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
                                  llvm::Value *&Receiver,
                                  llvm::Value *cmd,
-                                 llvm::MDNode *node) = 0;
+                                 llvm::MDNode *node,
+                                 MessageSendInfo &MSI) = 0;
   /// Looks up the method for sending a message to a superclass.  This
   /// mechanism differs between the GCC and GNU runtimes, so this method must
   /// be overridden in subclasses.
   virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
                                       llvm::Value *ObjCSuper,
-                                      llvm::Value *cmd) = 0;
+                                      llvm::Value *cmd,
+                                      MessageSendInfo &MSI) = 0;
   /// Libobjc2 uses a bitfield representation where small(ish) bitfields are
   /// stored in a 64-bit value with the low bit set to 1 and the remaining 63
   /// bits set to their values, LSB first, while larger ones are stored in a
@@ -596,7 +598,8 @@ protected:
   virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
                                  llvm::Value *&Receiver,
                                  llvm::Value *cmd,
-                                 llvm::MDNode *node) {
+                                 llvm::MDNode *node,
+                                 MessageSendInfo &MSI) {
     CGBuilderTy &Builder = CGF.Builder;
     llvm::Value *args[] = {
             EnforceType(Builder, Receiver, IdTy),
@@ -607,7 +610,8 @@ protected:
   }
   virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
                                       llvm::Value *ObjCSuper,
-                                      llvm::Value *cmd) {
+                                      llvm::Value *cmd,
+                                      MessageSendInfo &MSI) {
       CGBuilderTy &Builder = CGF.Builder;
       llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
           PtrToObjCSuperTy), cmd};
@@ -655,7 +659,8 @@ class CGObjCGNUstep : public CGObjCGNU {
     virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
                                    llvm::Value *&Receiver,
                                    llvm::Value *cmd,
-                                   llvm::MDNode *node) {
+                                   llvm::MDNode *node,
+                                   MessageSendInfo &MSI) {
       CGBuilderTy &Builder = CGF.Builder;
       llvm::Function *LookupFn = SlotLookupFn;
 
@@ -693,7 +698,8 @@ class CGObjCGNUstep : public CGObjCGNU {
     }
     virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
                                         llvm::Value *ObjCSuper,
-                                        llvm::Value *cmd) {
+                                        llvm::Value *cmd,
+                                        MessageSendInfo &MSI) {
       CGBuilderTy &Builder = CGF.Builder;
       llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
 
@@ -797,31 +803,46 @@ protected:
   /// The GCC ABI message lookup function.  Returns an IMP pointing to the
   /// method implementation for this message.
   LazyRuntimeFunction MsgLookupFn;
+  /// stret lookup function.  While this does not seem to make sense at the
+  /// first look, this is required to call the correct forwarding function.
+  LazyRuntimeFunction MsgLookupFnSRet;
   /// The GCC ABI superclass message lookup function.  Takes a pointer to a
   /// structure describing the receiver and the class, and a selector as
   /// arguments.  Returns the IMP for the corresponding method.
-  LazyRuntimeFunction MsgLookupSuperFn;
+  LazyRuntimeFunction MsgLookupSuperFn, MsgLookupSuperFnSRet;
 
   virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
                                  llvm::Value *&Receiver,
                                  llvm::Value *cmd,
-                                 llvm::MDNode *node) {
+                                 llvm::MDNode *node,
+                                 MessageSendInfo &MSI) {
     CGBuilderTy &Builder = CGF.Builder;
     llvm::Value *args[] = {
             EnforceType(Builder, Receiver, IdTy),
             EnforceType(Builder, cmd, SelectorTy) };
-    llvm::CallSite imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
+
+    llvm::CallSite imp;
+    if (CGM.ReturnTypeUsesSRet(MSI.CallInfo))
+      imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFnSRet, args);
+    else
+      imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
+
     imp->setMetadata(msgSendMDKind, node);
     return imp.getInstruction();
   }
 
   virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
                                       llvm::Value *ObjCSuper,
-                                      llvm::Value *cmd) {
+                                      llvm::Value *cmd,
+                                      MessageSendInfo &MSI) {
       CGBuilderTy &Builder = CGF.Builder;
       llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
           PtrToObjCSuperTy), cmd};
-      return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
+
+      if (CGM.ReturnTypeUsesSRet(MSI.CallInfo))
+        return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFnSRet, lookupArgs);
+      else
+        return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
     }
 
   virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
@@ -847,9 +868,13 @@ public:
   CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) {
     // IMP objc_msg_lookup(id, SEL);
     MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, NULL);
+    MsgLookupFnSRet.init(&CGM, "objc_msg_lookup_stret", IMPTy, IdTy,
+                         SelectorTy, NULL);
     // IMP objc_msg_lookup_super(struct objc_super*, SEL);
     MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
                           PtrToObjCSuperTy, SelectorTy, NULL);
+    MsgLookupSuperFnSRet.init(&CGM, "objc_msg_lookup_super_stret", IMPTy,
+                              PtrToObjCSuperTy, SelectorTy, NULL);
   }
 };
 } // end anonymous namespace
@@ -1291,7 +1316,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
   ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy);
 
   // Get the IMP
-  llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd);
+  llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd, MSI);
   imp = EnforceType(Builder, imp, MSI.MessengerType);
 
   llvm::Value *impMD[] = {
@@ -1390,7 +1415,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
   // given platform), so we 
   switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
     case CodeGenOptions::Legacy:
-      imp = LookupIMP(CGF, Receiver, cmd, node);
+      imp = LookupIMP(CGF, Receiver, cmd, node, MSI);
       break;
     case CodeGenOptions::Mixed:
     case CodeGenOptions::NonLegacy:
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index d21515c..469d5eb 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -743,6 +743,7 @@ static bool HasFeature(const Preprocessor &PP, const \
                IdentifierInfo *II) {
            .Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile())
            .Case("objc_property_explicit_atomic", true) // Does clang support \
                explicit "atomic" keyword?
            .Case("objc_weak_class", LangOpts.ObjCRuntime.hasWeakClassImport())
+           .Case("objc_msg_lookup_stret", LangOpts.ObjCRuntime.getKind() == \
                ObjCRuntime::ObjFW)
            .Case("ownership_holds", true)
            .Case("ownership_returns", true)
            .Case("ownership_takes", true)
diff --git a/test/CodeGenObjC/stret_lookup.m b/test/CodeGenObjC/stret_lookup.m
new file mode 100644
index 0000000..c9ac713
--- /dev/null
+++ b/test/CodeGenObjC/stret_lookup.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -DSTRET -triple x86_64-pc-linux-gnu -fobjc-runtime=objfw \
-emit-llvm -o - %s | FileCheck -check-prefix=HASSTRET %s +// RUN: %clang_cc1 -triple \
x86_64-pc-linux-gnu -fobjc-runtime=gcc -emit-llvm -o - %s | FileCheck \
-check-prefix=NOSTRET %s +
+// Test stret lookup
+
+struct test {
+  char test[1024];
+};
+@interface Test0
++ (struct test)test;
+@end
+void test0(void) {
+  struct test t;
+#if (defined(STRET) && __has_feature(objc_msg_lookup_stret)) || \
+    (!defined(STRET) && !__has_feature(objc_msg_lookup_stret))
+  t = [Test0 test];
+#endif
+  (void)t;
+}
+
+// HASSTRET: define void @test0()
+// HASSTRET: [[T0:%.*]] = call i8* (i8*, i8*, ...)* (i8*, i8*)* \
@objc_msg_lookup_stret(i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*), +// \
HASSTRET-NEXT: [[T1:%.*]] = bitcast i8* (i8*, i8*, ...)* [[T0]] to void \
(%struct.test*, i8*, i8*)* +// HASSTRET-NEXT: call void [[T1]](%struct.test* sret \
%tmp, i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*), +
+// NOSTRET: define void @test0()
+// NOSTRET: [[T0:%.*]] = call i8* (i8*, i8*, ...)* (i8*, i8*)* @objc_msg_lookup(i8* \
%0, +// NOSTRET-NEXT: [[T1:%.*]] = bitcast i8* (i8*, i8*, ...)* [[T0]] to void \
(%struct.test*, i8*, i8*)* +// NOSTRET-NEXT: call void [[T1]](%struct.test* sret \
                %tmp, i8* %0, i8* bitcast ([2 x { i8*, i8* }]*
-- 
Jonathan



_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic