diff options
Diffstat (limited to 'test/CodeGen/aggregate-assign-call.c')
-rw-r--r-- | test/CodeGen/aggregate-assign-call.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/test/CodeGen/aggregate-assign-call.c b/test/CodeGen/aggregate-assign-call.c new file mode 100644 index 0000000000000..83983722db945 --- /dev/null +++ b/test/CodeGen/aggregate-assign-call.c @@ -0,0 +1,93 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O1 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=O1 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O0 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=O0 +// +// Ensure that we place appropriate lifetime markers around indirectly returned +// temporaries, and that the lifetime.ends appear in a timely manner. +// +// -O1 is used so lifetime markers actually get emitted. + +struct S { + int ns[40]; +}; + +struct S foo(void); + +// CHECK-LABEL: define dso_local void @bar +struct S bar() { + // O0-NOT: @llvm.lifetime.start + // O0-NOT: @llvm.lifetime.end + + struct S r; + // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* nonnull %[[TMP1:[^)]+]]) + // O1: call void @foo + r = foo(); + // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %[[TMP1]]) + + // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* nonnull %[[TMP2:[^)]+]]) + // O1: call void @foo + r = foo(); + // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %[[TMP2]]) + + // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* nonnull %[[TMP3:[^)]+]]) + // O1: call void @foo + r = foo(); + // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %[[TMP3]]) + + return r; +} + +struct S foo_int(int); + +// Be sure that we're placing the lifetime.end so that all paths go through it. +// Since this function turns out to be large-ish, optnone to hopefully keep it +// stable. +// CHECK-LABEL: define dso_local void @baz +__attribute__((optnone)) +struct S baz(int i, volatile int *j) { + // O0-NOT: @llvm.lifetime.start + // O0-NOT: @llvm.lifetime.end + + struct S r; + // O1: %[[TMP1_ALLOCA:[^ ]+]] = alloca %struct.S + // O1: %[[TMP2_ALLOCA:[^ ]+]] = alloca %struct.S + // O1: br label %[[DO_BODY:.+]] + + do { + // O1: [[DO_BODY]]: + // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8* + // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* %[[P]]) + // O1: br i1 {{[^,]+}}, label %[[IF_THEN:[^,]+]], label %[[IF_END:[^,]+]] + // + // O1: [[IF_THEN]]: + // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8* + // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) + // O1: br label %[[DO_END:.*]] + // + // O1: [[IF_END]]: + // O1: call void @foo_int(%struct.S* sret %[[TMP1_ALLOCA]], + // O1: call void @llvm.memcpy + // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8* + // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) + // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* + // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* %[[P]]) + // O1: call void @foo_int(%struct.S* sret %[[TMP2_ALLOCA]], + // O1: call void @llvm.memcpy + // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* + // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) + // O1: br label %[[DO_COND:.*]] + // + // O1: [[DO_COND]]: + // O1: br label %[[DO_BODY]] + r = foo_int(({ + if (*j) + break; + i++; + })); + + r = foo_int(i++); + } while (1); + + // O1: [[DO_END]]: + // O1-NEXT: ret void + return r; +} |