xref: /llvm-project/clang/test/CodeGen/aggregate-assign-call.c (revision c5de4dd1eab00df76c1a68c5f397304ceacb71f2)
1 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O1 -emit-llvm -o - %s | FileCheck %s --check-prefixes=O1
2 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O0 -emit-llvm -o - %s | FileCheck %s --check-prefix=O0
3 //
4 // Ensure that we place appropriate lifetime markers around indirectly returned
5 // temporaries, and that the lifetime.ends appear in a timely manner.
6 //
7 // -O1 is used so lifetime markers actually get emitted and optnone is added
8 // to avoid elimination of lifetime markers by optimizations.
9 
10 struct S {
11   int ns[40];
12 };
13 
14 struct S foo(void);
15 
16 // CHECK-LABEL: define dso_local void @bar
17 __attribute__((optnone))
bar(void)18 struct S bar(void) {
19   // O0-NOT: @llvm.lifetime.start
20   // O0-NOT: @llvm.lifetime.end
21 
22   struct S r;
23   // O1: %[[TMP1_ALLOCA:[^ ]+]] = alloca %struct.S
24   // O1: %[[TMP2_ALLOCA:[^ ]+]] = alloca %struct.S
25   // O1: %[[TMP3_ALLOCA:[^ ]+]] = alloca %struct.S
26 
27   // O1: call void @llvm.lifetime.start.p0({{[^,]*}}, ptr %[[TMP1_ALLOCA]])
28   // O1: call void @foo
29   r = foo();
30   // O1: memcpy
31   // O1: call void @llvm.lifetime.end.p0({{[^,]*}}, ptr %[[TMP1_ALLOCA]])
32 
33   // O1: call void @llvm.lifetime.start.p0({{[^,]*}}, ptr %[[TMP2_ALLOCA]])
34   // O1: call void @foo
35   r = foo();
36   // O1: memcpy
37   // O1: call void @llvm.lifetime.end.p0({{[^,]*}}, ptr %[[TMP2_ALLOCA]])
38 
39   // O1: call void @llvm.lifetime.start.p0({{[^,]*}}, ptr %[[TMP3_ALLOCA]])
40   // O1: call void @foo
41   r = foo();
42   // O1: memcpy
43   // O1: call void @llvm.lifetime.end.p0({{[^,]*}}, ptr %[[TMP3_ALLOCA]])
44 
45   return r;
46 }
47 
48 struct S foo_int(int);
49 
50 // Be sure that we're placing the lifetime.end so that all paths go through it.
51 // CHECK-LABEL: define dso_local void @baz
52 __attribute__((optnone))
baz(int i,volatile int * j)53 struct S baz(int i, volatile int *j) {
54   // O0-NOT: @llvm.lifetime.start
55   // O0-NOT: @llvm.lifetime.end
56 
57   struct S r;
58   // O1: %[[TMP1_ALLOCA:[^ ]+]] = alloca %struct.S
59   // O1: %[[TMP2_ALLOCA:[^ ]+]] = alloca %struct.S
60 
61   do {
62     // O1: call void @llvm.lifetime.start.p0({{[^,]*}}, ptr %[[TMP1_ALLOCA]])
63     //
64     // O1: call void @llvm.lifetime.end.p0({{[^,]*}}, ptr %[[TMP1_ALLOCA]])
65     //
66     // O1: call void @foo_int(ptr dead_on_unwind writable sret(%struct.S) align 4 %[[TMP1_ALLOCA]],
67     // O1: call void @llvm.memcpy
68     // O1: call void @llvm.lifetime.end.p0({{[^,]*}}, ptr %[[TMP1_ALLOCA]])
69     // O1: call void @llvm.lifetime.start.p0({{[^,]*}}, ptr %[[TMP2_ALLOCA]])
70     // O1: call void @foo_int(ptr dead_on_unwind writable sret(%struct.S) align 4 %[[TMP2_ALLOCA]],
71     // O1: call void @llvm.memcpy
72     // O1: call void @llvm.lifetime.end.p0({{[^,]*}}, ptr %[[TMP2_ALLOCA]])
73     r = foo_int(({
74       if (*j)
75         break;
76       i++;
77     }));
78 
79     r = foo_int(i++);
80    } while (1);
81 
82   return r;
83 }
84