[PATCH] D44968: [ObjC] Generalize NRVO to cover non-trivial C structs

2018-03-27 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

Is it possible to just do this for all structs?  I don't think it hurts 
anything to do it for structs that are trivial and returned indirectly, and it 
would certainly be nice to construct C return values in-place even if they're 
guilty of nothing more than being, y'know, really really big.




Comment at: lib/CodeGen/CGDecl.cpp:1116
   if (const RecordType *RecordTy = Ty->getAs()) {
-if (!cast(RecordTy->getDecl())->hasTrivialDestructor()) 
{
+const auto *RD = cast(RecordTy->getDecl());
+const auto *CXXRD = dyn_cast(RD);

I think this cast isn't necessary.


Repository:
  rC Clang

https://reviews.llvm.org/D44968



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D44968: [ObjC] Generalize NRVO to cover non-trivial C structs

2018-03-27 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added reviewers: rjmccall, doug.gregor, rsmith.

r326307 and r327870 made changes that allowed using non-trivial C
structs with fields qualified with __strong or __weak. This commit generalizes 
NRVO, which could only be applied to C++ structs, to cover non-trivial C 
structs.


Repository:
  rC Clang

https://reviews.llvm.org/D44968

Files:
  lib/CodeGen/CGDecl.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaStmt.cpp
  test/CodeGenObjC/objc-non-trivial-struct-nrvo.m

Index: test/CodeGenObjC/objc-non-trivial-struct-nrvo.m
===
--- /dev/null
+++ test/CodeGenObjC/objc-non-trivial-struct-nrvo.m
@@ -0,0 +1,111 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck %s
+
+// CHECK: %[[STRUCT_TRIVIAL:.*]] = type { i32 }
+// CHECK: %[[STRUCT_STRONG:.*]] = type { i8* }
+// CHECK: %[[STRUCT_WEAK:.*]] = type { i8* }
+
+typedef struct {
+  int x;
+} Trivial;
+
+typedef struct {
+  id x;
+} Strong;
+
+typedef struct {
+  __weak id x;
+} Weak;
+
+// CHECK: define i32 @testTrivial()
+// CHECK-NOT: br
+// CHECK: ret i32 %{{.*}}
+
+Trivial testTrivial() {
+  Trivial a;
+  return a;
+}
+
+// CHECK: define i8* @testStrong()
+// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8
+// CHECK: %[[NRVO:.*]] = alloca i1, align 1
+// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONG]]* %[[RETVAL]] to i8**
+// CHECK: call void @__default_constructor_8_s0(i8** %[[V0]])
+// CHECK: store i1 true, i1* %[[NRVO]], align 1
+// CHECK: %[[NRVO_VAL:.*]] = load i1, i1* %[[NRVO]], align 1
+// CHECK: br i1 %[[NRVO_VAL]],
+
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONG]]* %[[RETVAL]] to i8**
+// CHECK: call void @__destructor_8_s0(i8** %[[V1]])
+// CHECK: br
+
+// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[RETVAL]], i32 0, i32 0
+// CHECK: %[[V2:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8
+// CHECK: ret i8* %[[V2]]
+
+Strong testStrong() {
+  Strong a;
+  return a;
+}
+
+// CHECK: define void @testWeak(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]])
+// CHECK: %[[NRVO:.*]] = alloca i1, align 1
+// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8**
+// CHECK: call void @__default_constructor_8_w0(i8** %[[V0]])
+// CHECK: store i1 true, i1* %[[NRVO]], align 1
+// CHECK: %[[NRVO_VAL:.*]] = load i1, i1* %[[NRVO]], align 1
+// CHECK: br i1 %[[NRVO_VAL]],
+
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8**
+// CHECK: call void @__destructor_8_w0(i8** %[[V1]]) #3
+// CHECK: br
+
+// CHECK-NOT: call
+// CHECK: ret void
+
+Weak testWeak() {
+  Weak a;
+  return a;
+}
+
+// CHECK: define void @testWeak2(
+// CHECK: call void @__default_constructor_8_w0(
+// CHECK: call void @__default_constructor_8_w0(
+// CHECK: call void @__copy_constructor_8_8_w0(
+// CHECK: call void @__copy_constructor_8_8_w0(
+// CHECK: call void @__destructor_8_w0(
+// CHECK: call void @__destructor_8_w0(
+
+Weak testWeak2(int c) {
+  Weak a, b;
+  if (c)
+return a;
+  else
+return b;
+}
+
+// CHECK: define internal void @"\01-[C1 foo1]"(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]], %{{.*}}* %{{.*}}, i8* %{{.*}})
+// CHECK: %[[NRVO:.*]] = alloca i1, align 1
+// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8**
+// CHECK: call void @__default_constructor_8_w0(i8** %[[V0]])
+// CHECK: store i1 true, i1* %[[NRVO]], align 1
+// CHECK: %[[NRVO_VAL:.*]] = load i1, i1* %[[NRVO]], align 1
+// CHECK: br i1 %[[NRVO_VAL]],
+
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8**
+// CHECK: call void @__destructor_8_w0(i8** %[[V1]])
+// CHECK: br
+
+// CHECK-NOT: call
+// CHECK: ret void
+
+__attribute__((objc_root_class))
+@interface C1
+- (Weak)foo1;
+@end
+
+@implementation C1
+- (Weak)foo1 {
+  Weak a;
+  return a;
+}
+@end
Index: lib/Sema/SemaStmt.cpp
===
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -2872,7 +2872,7 @@
 /// NRVO, or NULL if there is no such candidate.
 VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, Expr *E,
CopyElisionSemanticsKind CESK) {
-  if (!getLangOpts().CPlusPlus)
+  if (!getLangOpts().CPlusPlus && !ReturnType.isNonTrivialToPrimitiveCopy())
 return nullptr;
 
   // - in a return statement in a function [where] ...
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12712,8 +12712,10 @@
   // Try to apply the named return value optimization. We have to check
   // if we can do this here because lambdas keep return statements around
   // to deduce an implicit return type.
-  if (getLangOpts().CPlusPlus && FD->getReturnType()->isRecordType() &&
-  !FD->isDependentContext())
+  QualType RetTy = FD-