1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
2 ; RUN: opt < %s -passes='require<globals-aa>,memcpyopt' -S -verify-memoryssa | FileCheck %s
4 target datalayout = "e"
7 declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1) nounwind
8 declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
9 declare void @llvm.lifetime.end.p0(i64, ptr nocapture)
11 ; Check that the transformation isn't applied if the called function can
12 ; capture the pointer argument (i.e. the nocapture attribute isn't present)
14 ; CHECK-LABEL: define {{[^@]+}}@test() {
15 ; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1
16 ; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1
17 ; CHECK-NEXT: call void @foo(ptr [[PTR2]])
18 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false)
19 ; CHECK-NEXT: call void @foo(ptr [[PTR1]])
20 ; CHECK-NEXT: ret void
24 call void @foo(ptr %ptr2)
25 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
26 call void @foo(ptr %ptr1)
30 ; Same as previous test, but with a bitcasted argument.
31 define void @test_bitcast() {
32 ; CHECK-LABEL: define {{[^@]+}}@test_bitcast() {
33 ; CHECK-NEXT: [[PTR1:%.*]] = alloca [2 x i8], align 1
34 ; CHECK-NEXT: [[PTR2:%.*]] = alloca [2 x i8], align 1
35 ; CHECK-NEXT: call void @foo(ptr [[PTR2]])
36 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 2, i1 false)
37 ; CHECK-NEXT: call void @foo(ptr [[PTR1]])
38 ; CHECK-NEXT: ret void
40 %ptr1 = alloca [2 x i8]
41 %ptr2 = alloca [2 x i8]
42 call void @foo(ptr %ptr2)
43 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 2, i1 false)
44 call void @foo(ptr %ptr1)
48 ; Lifetime of %ptr2 ends before the potential use of the capture in the second
50 define void @test_lifetime_end() {
51 ; CHECK-LABEL: define {{[^@]+}}@test_lifetime_end() {
52 ; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1
53 ; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1
54 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[PTR2]])
55 ; CHECK-NEXT: call void @foo(ptr [[PTR1]])
56 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[PTR2]])
57 ; CHECK-NEXT: call void @foo(ptr [[PTR1]])
58 ; CHECK-NEXT: ret void
62 call void @llvm.lifetime.start.p0(i64 1, ptr %ptr2)
63 call void @foo(ptr %ptr2)
64 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
65 call void @llvm.lifetime.end.p0(i64 1, ptr %ptr2)
66 call void @foo(ptr %ptr1)
70 ; Lifetime of %ptr2 does not end, because of size mismatch.
71 define void @test_lifetime_not_end() {
72 ; CHECK-LABEL: define {{[^@]+}}@test_lifetime_not_end() {
73 ; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1
74 ; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1
75 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[PTR2]])
76 ; CHECK-NEXT: call void @foo(ptr [[PTR2]])
77 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false)
78 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 0, ptr [[PTR2]])
79 ; CHECK-NEXT: call void @foo(ptr [[PTR1]])
80 ; CHECK-NEXT: ret void
84 call void @llvm.lifetime.start.p0(i64 1, ptr %ptr2)
85 call void @foo(ptr %ptr2)
86 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
87 call void @llvm.lifetime.end.p0(i64 0, ptr %ptr2)
88 call void @foo(ptr %ptr1)
92 ; Lifetime of %ptr2 ends before any potential use of the capture because we
93 ; return from the function.
94 define void @test_function_end() {
95 ; CHECK-LABEL: define {{[^@]+}}@test_function_end() {
96 ; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1
97 ; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1
98 ; CHECK-NEXT: call void @foo(ptr [[PTR1]])
99 ; CHECK-NEXT: ret void
103 call void @foo(ptr %ptr2)
104 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
108 ; A potential use of the capture occurs in a later block, can't be optimized.
109 define void @test_terminator() {
110 ; CHECK-LABEL: define {{[^@]+}}@test_terminator() {
111 ; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1
112 ; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1
113 ; CHECK-NEXT: call void @foo(ptr [[PTR2]])
114 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false)
115 ; CHECK-NEXT: br label [[NEXT:%.*]]
117 ; CHECK-NEXT: call void @foo(ptr [[PTR1]])
118 ; CHECK-NEXT: ret void
122 call void @foo(ptr %ptr2)
123 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
127 call void @foo(ptr %ptr1)
131 ; This case can be optimized, but would require a scan across multiple blocks
132 ; and is currently not performed.
133 define void @test_terminator2() {
134 ; CHECK-LABEL: define {{[^@]+}}@test_terminator2() {
135 ; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1
136 ; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1
137 ; CHECK-NEXT: call void @foo(ptr [[PTR2]])
138 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false)
139 ; CHECK-NEXT: br label [[NEXT:%.*]]
141 ; CHECK-NEXT: ret void
145 call void @foo(ptr %ptr2)
146 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
153 declare void @capture(ptr)
155 ; This case should not be optimized, because dest is captured before the call.
156 define void @test_dest_captured_before_alloca() {
157 ; CHECK-LABEL: define {{[^@]+}}@test_dest_captured_before_alloca() {
158 ; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1
159 ; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1
160 ; CHECK-NEXT: call void @capture(ptr [[PTR1]])
161 ; CHECK-NEXT: call void @foo(ptr [[PTR2]]) #[[ATTR2:[0-9]+]]
162 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false)
163 ; CHECK-NEXT: ret void
167 call void @capture(ptr %ptr1)
168 call void @foo(ptr %ptr2) argmemonly
169 call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
174 @g = internal global i8 0
176 ; This case should not be optimized, because @g is captured before the call
177 ; (being a global) and @icmp_g might depend on its identity.
178 define void @test_dest_captured_before_global() {
179 ; CHECK-LABEL: define {{[^@]+}}@test_dest_captured_before_global() {
180 ; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1
181 ; CHECK-NEXT: call void @icmp_g(ptr [[PTR]])
182 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr @g, ptr [[PTR]], i32 1, i1 false)
183 ; CHECK-NEXT: ret void
186 call void @icmp_g(ptr %ptr)
187 call void @llvm.memcpy.p0.p0.i32(ptr @g, ptr %ptr, i32 1, i1 false)
191 define void @icmp_g(ptr %p) {
192 ; CHECK-LABEL: define {{[^@]+}}@icmp_g
193 ; CHECK-SAME: (ptr [[P:%.*]]) {
194 ; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P]], @g
195 ; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
197 ; CHECK-NEXT: store i8 1, ptr [[P]], align 1
198 ; CHECK-NEXT: ret void
200 ; CHECK-NEXT: store i8 2, ptr [[P]], align 1
201 ; CHECK-NEXT: ret void
203 %c = icmp eq ptr %p, @g
204 br i1 %c, label %if, label %else