Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / test / CodeGen / aarch64-byval-temp.c
blobe9e2586406e5c13173ae92c242c076598605e5ff
1 // RUN: %clang_cc1 -emit-llvm -triple arm64-- -o - %s -O0 | FileCheck %s --check-prefix=CHECK-O0
2 // RUN: %clang_cc1 -emit-llvm -disable-llvm-optzns -triple arm64-- -o - %s -O3 | FileCheck %s --check-prefix=CHECK-O3
4 struct large {
5 void* pointers[8];
6 };
8 void pass_large(struct large);
10 // For arm64, we don't use byval to pass structs but instead we create
11 // temporary allocas.
13 // Make sure we generate the appropriate lifetime markers for the temporary
14 // allocas so that the optimizer can re-use stack slots if possible.
15 void example(void) {
16 struct large l = {0};
17 pass_large(l);
18 pass_large(l);
20 // CHECK-O0-LABEL: define{{.*}} void @example(
21 // The alloca for the struct on the stack.
22 // CHECK-O0: %[[l:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
23 // The alloca for the temporary stack space that we use to pass the argument.
24 // CHECK-O0-NEXT: %[[byvaltemp:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
25 // Another one to pass the argument to the second function call.
26 // CHECK-O0-NEXT: %[[byvaltemp1:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
27 // First, memset `l` to 0.
28 // CHECK-O0-NEXT: call void @llvm.memset.p0.i64(ptr align 8 %[[l]], i8 0, i64 64, i1 false)
29 // Then, memcpy `l` to the temporary stack space.
30 // CHECK-O0-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp]], ptr align 8 %[[l]], i64 64, i1 false)
31 // Finally, call using a pointer to the temporary stack space.
32 // CHECK-O0-NEXT: call void @pass_large(ptr noundef %[[byvaltemp]])
33 // Now, do the same for the second call, using the second temporary alloca.
34 // CHECK-O0-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp1]], ptr align 8 %[[l]], i64 64, i1 false)
35 // CHECK-O0-NEXT: call void @pass_large(ptr noundef %[[byvaltemp1]])
36 // CHECK-O0-NEXT: ret void
38 // At O3, we should have lifetime markers to help the optimizer re-use the temporary allocas.
40 // CHECK-O3-LABEL: define{{.*}} void @example(
41 // The alloca for the struct on the stack.
42 // CHECK-O3: %[[l:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
43 // The alloca for the temporary stack space that we use to pass the argument.
44 // CHECK-O3-NEXT: %[[byvaltemp:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
45 // Another one to pass the argument to the second function call.
46 // CHECK-O3-NEXT: %[[byvaltemp1:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
48 // Mark the start of the lifetime for `l`
49 // CHECK-O3-NEXT: call void @llvm.lifetime.start.p0(i64 64, ptr %[[l]])
51 // First, memset `l` to 0.
52 // CHECK-O3-NEXT: call void @llvm.memset.p0.i64(ptr align 8 %[[l]], i8 0, i64 64, i1 false)
54 // Lifetime of the first temporary starts here and ends right after the call.
55 // CHECK-O3-NEXT: call void @llvm.lifetime.start.p0(i64 64, ptr %[[byvaltemp]])
57 // Then, memcpy `l` to the temporary stack space.
58 // CHECK-O3-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp]], ptr align 8 %[[l]], i64 64, i1 false)
59 // Finally, call using a pointer to the temporary stack space.
60 // CHECK-O3-NEXT: call void @pass_large(ptr noundef %[[byvaltemp]])
62 // The lifetime of the temporary used to pass a pointer to the struct ends here.
63 // CHECK-O3-NEXT: call void @llvm.lifetime.end.p0(i64 64, ptr %[[byvaltemp]])
65 // Now, do the same for the second call, using the second temporary alloca.
66 // CHECK-O3-NEXT: call void @llvm.lifetime.start.p0(i64 64, ptr %[[byvaltemp1]])
67 // CHECK-O3-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp1]], ptr align 8 %[[l]], i64 64, i1 false)
68 // CHECK-O3-NEXT: call void @pass_large(ptr noundef %[[byvaltemp1]])
69 // CHECK-O3-NEXT: call void @llvm.lifetime.end.p0(i64 64, ptr %[[byvaltemp1]])
71 // Mark the end of the lifetime of `l`.
72 // CHECK-O3-NEXT: call void @llvm.lifetime.end.p0(i64 64, ptr %l)
73 // CHECK-O3-NEXT: ret void