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-