[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / MemCpyOpt / memset-memcpy-oversized.ll
blobab85e4de5c56ff5a913043ce19a3691b597ee38d
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -memcpyopt -S %s -verify-memoryssa | FileCheck %s
4 ; memset -> memcpy forwarding, if memcpy is larger than memset, but trailing
5 ; bytes are known to be undef.
8 %T = type { i64, i32, i32 }
10 define void @test_alloca(i8* %result) {
11 ; CHECK-LABEL: @test_alloca(
12 ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
13 ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
14 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8 0, i64 12, i1 false)
15 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8 0, i64 12, i1 false)
16 ; CHECK-NEXT:    ret void
18   %a = alloca %T, align 8
19   %b = bitcast %T* %a to i8*
20   call void @llvm.memset.p0i8.i64(i8* align 8 %b, i8 0, i64 12, i1 false)
21   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %b, i64 16, i1 false)
22   ret void
25 define void @test_alloca_with_lifetimes(i8* %result) {
26 ; CHECK-LABEL: @test_alloca_with_lifetimes(
27 ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
28 ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
29 ; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 16, i8* [[B]])
30 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8 0, i64 12, i1 false)
31 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8 0, i64 12, i1 false)
32 ; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 16, i8* [[B]])
33 ; CHECK-NEXT:    ret void
35   %a = alloca %T, align 8
36   %b = bitcast %T* %a to i8*
37   call void @llvm.lifetime.start.p0i8(i64 16, i8* %b)
38   call void @llvm.memset.p0i8.i64(i8* align 8 %b, i8 0, i64 12, i1 false)
39   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %b, i64 16, i1 false)
40   call void @llvm.lifetime.end.p0i8(i64 16, i8* %b)
41   ret void
44 define void @test_malloc_with_lifetimes(i8* %result) {
45 ; CHECK-LABEL: @test_malloc_with_lifetimes(
46 ; CHECK-NEXT:    [[A:%.*]] = call i8* @malloc(i64 16)
47 ; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 16, i8* [[A]])
48 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[A]], i8 0, i64 12, i1 false)
49 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8 0, i64 12, i1 false)
50 ; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 16, i8* [[A]])
51 ; CHECK-NEXT:    call void @free(i8* [[A]])
52 ; CHECK-NEXT:    ret void
54   %a = call i8* @malloc(i64 16)
55   call void @llvm.lifetime.start.p0i8(i64 16, i8* %a)
56   call void @llvm.memset.p0i8.i64(i8* align 8 %a, i8 0, i64 12, i1 false)
57   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %a, i64 16, i1 false)
58   call void @llvm.lifetime.end.p0i8(i64 16, i8* %a)
59   call void @free(i8* %a)
60   ret void
63 ; memcpy size is larger than lifetime, don't optimize.
64 define void @test_copy_larger_than_lifetime_size(i8* %result) {
65 ; CHECK-LABEL: @test_copy_larger_than_lifetime_size(
66 ; CHECK-NEXT:    [[A:%.*]] = call i8* @malloc(i64 16)
67 ; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 12, i8* [[A]])
68 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[A]], i8 0, i64 12, i1 false)
69 ; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[RESULT:%.*]], i8* align 8 [[A]], i64 16, i1 false)
70 ; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 12, i8* [[A]])
71 ; CHECK-NEXT:    call void @free(i8* [[A]])
72 ; CHECK-NEXT:    ret void
74   %a = call i8* @malloc(i64 16)
75   call void @llvm.lifetime.start.p0i8(i64 12, i8* %a)
76   call void @llvm.memset.p0i8.i64(i8* align 8 %a, i8 0, i64 12, i1 false)
77   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %a, i64 16, i1 false)
78   call void @llvm.lifetime.end.p0i8(i64 12, i8* %a)
79   call void @free(i8* %a)
80   ret void
83 ; The trailing bytes are not known to be undef, we can't ignore them.
84 define void @test_not_undef_memory(i8* %result, i8* %input) {
85 ; CHECK-LABEL: @test_not_undef_memory(
86 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[INPUT:%.*]], i8 0, i64 12, i1 false)
87 ; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[RESULT:%.*]], i8* align 8 [[INPUT]], i64 16, i1 false)
88 ; CHECK-NEXT:    ret void
90   call void @llvm.memset.p0i8.i64(i8* align 8 %input, i8 0, i64 12, i1 false)
91   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %input, i64 16, i1 false)
92   ret void
95 ; Memset is volatile, memcpy is not. Can be optimized.
96 define void @test_volatile_memset(i8* %result) {
97 ; CHECK-LABEL: @test_volatile_memset(
98 ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
99 ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
100 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8 0, i64 12, i1 true)
101 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8 0, i64 12, i1 false)
102 ; CHECK-NEXT:    ret void
104   %a = alloca %T, align 8
105   %b = bitcast %T* %a to i8*
106   call void @llvm.memset.p0i8.i64(i8* align 8 %b, i8 0, i64 12, i1 true)
107   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %b, i64 16, i1 false)
108   ret void
111 ; Memcpy is volatile, memset is not. Cannot be optimized.
112 define void @test_volatile_memcpy(i8* %result) {
113 ; CHECK-LABEL: @test_volatile_memcpy(
114 ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
115 ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
116 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8 0, i64 12, i1 false)
117 ; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 true)
118 ; CHECK-NEXT:    ret void
120   %a = alloca %T, align 8
121   %b = bitcast %T* %a to i8*
122   call void @llvm.memset.p0i8.i64(i8* align 8 %b, i8 0, i64 12, i1 false)
123   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %b, i64 16, i1 true)
124   ret void
127 ; Write between memset and memcpy, can't optimize.
128 define void @test_write_between(i8* %result) {
129 ; CHECK-LABEL: @test_write_between(
130 ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
131 ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
132 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8 0, i64 12, i1 false)
133 ; CHECK-NEXT:    store i8 -1, i8* [[B]], align 1
134 ; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 false)
135 ; CHECK-NEXT:    ret void
137   %a = alloca %T, align 8
138   %b = bitcast %T* %a to i8*
139   call void @llvm.memset.p0i8.i64(i8* align 8 %b, i8 0, i64 12, i1 false)
140   store i8 -1, i8* %b
141   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %b, i64 16, i1 false)
142   ret void
145 ; A write prior to the memset, which is part of the memset region.
146 ; We could optimize this, but currently don't, because the used memory location is imprecise.
147 define void @test_write_before_memset_in_memset_region(i8* %result) {
148 ; CHECK-LABEL: @test_write_before_memset_in_memset_region(
149 ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
150 ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
151 ; CHECK-NEXT:    store i8 -1, i8* [[B]], align 1
152 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8 0, i64 8, i1 false)
153 ; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 false)
154 ; CHECK-NEXT:    ret void
156   %a = alloca %T, align 8
157   %b = bitcast %T* %a to i8*
158   store i8 -1, i8* %b
159   call void @llvm.memset.p0i8.i64(i8* align 8 %b, i8 0, i64 8, i1 false)
160   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %b, i64 16, i1 false)
161   ret void
164 ; A write prior to the memset, which is part of the memcpy (but not memset) region.
165 ; This cannot be optimized.
166 define void @test_write_before_memset_in_memcpy_region(i8* %result) {
167 ; CHECK-LABEL: @test_write_before_memset_in_memcpy_region(
168 ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
169 ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
170 ; CHECK-NEXT:    [[C:%.*]] = getelementptr inbounds [[T]], %T* [[A]], i64 0, i32 2
171 ; CHECK-NEXT:    store i32 -1, i32* [[C]], align 4
172 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8 0, i64 8, i1 false)
173 ; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 false)
174 ; CHECK-NEXT:    ret void
176   %a = alloca %T, align 8
177   %b = bitcast %T* %a to i8*
178   %c = getelementptr inbounds %T, %T* %a, i64 0, i32 2
179   store i32 -1, i32* %c
180   call void @llvm.memset.p0i8.i64(i8* align 8 %b, i8 0, i64 8, i1 false)
181   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %b, i64 16, i1 false)
182   ret void
185 ; A write prior to the memset, which is part of both the memset and memcpy regions.
186 ; This cannot be optimized.
187 define void @test_write_before_memset_in_both_regions(i8* %result) {
188 ; CHECK-LABEL: @test_write_before_memset_in_both_regions(
189 ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
190 ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
191 ; CHECK-NEXT:    [[C:%.*]] = getelementptr inbounds [[T]], %T* [[A]], i64 0, i32 1
192 ; CHECK-NEXT:    store i32 -1, i32* [[C]], align 4
193 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8 0, i64 10, i1 false)
194 ; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 false)
195 ; CHECK-NEXT:    ret void
197   %a = alloca %T, align 8
198   %b = bitcast %T* %a to i8*
199   %c = getelementptr inbounds %T, %T* %a, i64 0, i32 1
200   store i32 -1, i32* %c
201   call void @llvm.memset.p0i8.i64(i8* align 8 %b, i8 0, i64 10, i1 false)
202   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %result, i8* align 8 %b, i64 16, i1 false)
203   ret void
206 declare i8* @malloc(i64)
207 declare void @free(i8*)
209 declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1)
210 declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i1)
212 declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
213 declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)