1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -memcpyopt -S < %s -verify-memoryssa | FileCheck %s
3
4target datalayout = "e-i64:64-f80:128-n8:16:32:64"
5target triple = "x86_64-unknown-linux-gnu"
6
7%S = type { i8*, i8, i32 }
8
9define void @copy(%S* %src, %S* %dst) {
10; CHECK-LABEL: @copy(
11; CHECK-NEXT:    [[TMP1:%.*]] = bitcast %S* [[DST:%.*]] to i8*
12; CHECK-NEXT:    [[TMP2:%.*]] = bitcast %S* [[SRC:%.*]] to i8*
13; CHECK-NEXT:    call void @llvm.memmove.p0i8.p0i8.i64(i8* align 8 [[TMP1]], i8* align 8 [[TMP2]], i64 16, i1 false)
14; CHECK-NEXT:    ret void
15;
16  %1 = load %S, %S* %src
17  store %S %1, %S* %dst
18  ret void
19}
20
21define void @noaliassrc(%S* noalias %src, %S* %dst) {
22; CHECK-LABEL: @noaliassrc(
23; CHECK-NEXT:    [[TMP1:%.*]] = bitcast %S* [[DST:%.*]] to i8*
24; CHECK-NEXT:    [[TMP2:%.*]] = bitcast %S* [[SRC:%.*]] to i8*
25; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[TMP1]], i8* align 8 [[TMP2]], i64 16, i1 false)
26; CHECK-NEXT:    ret void
27;
28  %1 = load %S, %S* %src
29  store %S %1, %S* %dst
30  ret void
31}
32
33define void @noaliasdst(%S* %src, %S* noalias %dst) {
34; CHECK-LABEL: @noaliasdst(
35; CHECK-NEXT:    [[TMP1:%.*]] = bitcast %S* [[DST:%.*]] to i8*
36; CHECK-NEXT:    [[TMP2:%.*]] = bitcast %S* [[SRC:%.*]] to i8*
37; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[TMP1]], i8* align 8 [[TMP2]], i64 16, i1 false)
38; CHECK-NEXT:    ret void
39;
40  %1 = load %S, %S* %src
41  store %S %1, %S* %dst
42  ret void
43}
44
45define void @destroysrc(%S* %src, %S* %dst) {
46; CHECK-LABEL: @destroysrc(
47; CHECK-NEXT:    [[TMP1:%.*]] = load [[S:%.*]], %S* [[SRC:%.*]], align 8
48; CHECK-NEXT:    [[TMP2:%.*]] = bitcast %S* [[SRC]] to i8*
49; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[TMP2]], i8 0, i64 16, i1 false)
50; CHECK-NEXT:    store [[S]] [[TMP1]], %S* [[DST:%.*]], align 8
51; CHECK-NEXT:    ret void
52;
53  %1 = load %S, %S* %src
54  store %S zeroinitializer, %S* %src
55  store %S %1, %S* %dst
56  ret void
57}
58
59define void @destroynoaliassrc(%S* noalias %src, %S* %dst) {
60; CHECK-LABEL: @destroynoaliassrc(
61; CHECK-NEXT:    [[TMP1:%.*]] = bitcast %S* [[SRC:%.*]] to i8*
62; CHECK-NEXT:    [[TMP2:%.*]] = bitcast %S* [[DST:%.*]] to i8*
63; CHECK-NEXT:    [[TMP3:%.*]] = bitcast %S* [[SRC]] to i8*
64; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[TMP2]], i8* align 8 [[TMP3]], i64 16, i1 false)
65; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[TMP1]], i8 0, i64 16, i1 false)
66; CHECK-NEXT:    ret void
67;
68  %1 = load %S, %S* %src
69  store %S zeroinitializer, %S* %src
70  store %S %1, %S* %dst
71  ret void
72}
73
74define void @copyalias(%S* %src, %S* %dst) {
75; CHECK-LABEL: @copyalias(
76; CHECK-NEXT:    [[TMP1:%.*]] = load [[S:%.*]], %S* [[SRC:%.*]], align 8
77; CHECK-NEXT:    [[TMP2:%.*]] = bitcast %S* [[DST:%.*]] to i8*
78; CHECK-NEXT:    [[TMP3:%.*]] = bitcast %S* [[SRC]] to i8*
79; CHECK-NEXT:    call void @llvm.memmove.p0i8.p0i8.i64(i8* align 8 [[TMP2]], i8* align 8 [[TMP3]], i64 16, i1 false)
80; CHECK-NEXT:    store [[S]] [[TMP1]], %S* [[DST]], align 8
81; CHECK-NEXT:    ret void
82;
83  %1 = load %S, %S* %src
84  %2 = load %S, %S* %src
85  store %S %1, %S* %dst
86  store %S %2, %S* %dst
87  ret void
88}
89
90; If the store address is computed in a complex manner, make
91; sure we lift the computation as well if needed and possible.
92define void @addrproducer(%S* %src, %S* %dst) {
93; CHECK-LABEL: @addrproducer(
94; CHECK-NEXT:    [[TMP1:%.*]] = bitcast %S* [[DST:%.*]] to i8*
95; CHECK-NEXT:    [[DST2:%.*]] = getelementptr [[S:%.*]], %S* [[DST]], i64 1
96; CHECK-NEXT:    [[TMP2:%.*]] = bitcast %S* [[DST2]] to i8*
97; CHECK-NEXT:    [[TMP3:%.*]] = bitcast %S* [[SRC:%.*]] to i8*
98; CHECK-NEXT:    call void @llvm.memmove.p0i8.p0i8.i64(i8* align 8 [[TMP2]], i8* align 8 [[TMP3]], i64 16, i1 false)
99; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[TMP1]], i8 undef, i64 16, i1 false)
100; CHECK-NEXT:    ret void
101;
102  %1 = load %S, %S* %src
103  store %S undef, %S* %dst
104  %dst2 = getelementptr %S , %S* %dst, i64 1
105  store %S %1, %S* %dst2
106  ret void
107}
108
109define void @aliasaddrproducer(%S* %src, %S* %dst, i32* %dstidptr) {
110; CHECK-LABEL: @aliasaddrproducer(
111; CHECK-NEXT:    [[TMP1:%.*]] = load [[S:%.*]], %S* [[SRC:%.*]], align 8
112; CHECK-NEXT:    [[TMP2:%.*]] = bitcast %S* [[DST:%.*]] to i8*
113; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[TMP2]], i8 undef, i64 16, i1 false)
114; CHECK-NEXT:    [[DSTINDEX:%.*]] = load i32, i32* [[DSTIDPTR:%.*]], align 4
115; CHECK-NEXT:    [[DST2:%.*]] = getelementptr [[S]], %S* [[DST]], i32 [[DSTINDEX]]
116; CHECK-NEXT:    store [[S]] [[TMP1]], %S* [[DST2]], align 8
117; CHECK-NEXT:    ret void
118;
119  %1 = load %S, %S* %src
120  store %S undef, %S* %dst
121  %dstindex = load i32, i32* %dstidptr
122  %dst2 = getelementptr %S , %S* %dst, i32 %dstindex
123  store %S %1, %S* %dst2
124  ret void
125}
126
127define void @noaliasaddrproducer(%S* %src, %S* noalias %dst, i32* noalias %dstidptr) {
128; CHECK-LABEL: @noaliasaddrproducer(
129; CHECK-NEXT:    [[TMP1:%.*]] = bitcast %S* [[SRC:%.*]] to i8*
130; CHECK-NEXT:    [[TMP2:%.*]] = load i32, i32* [[DSTIDPTR:%.*]], align 4
131; CHECK-NEXT:    [[DSTINDEX:%.*]] = or i32 [[TMP2]], 1
132; CHECK-NEXT:    [[DST2:%.*]] = getelementptr [[S:%.*]], %S* [[DST:%.*]], i32 [[DSTINDEX]]
133; CHECK-NEXT:    [[TMP3:%.*]] = bitcast %S* [[DST2]] to i8*
134; CHECK-NEXT:    [[TMP4:%.*]] = bitcast %S* [[SRC]] to i8*
135; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[TMP3]], i8* align 8 [[TMP4]], i64 16, i1 false)
136; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[TMP1]], i8 undef, i64 16, i1 false)
137; CHECK-NEXT:    ret void
138;
139  %1 = load %S, %S* %src
140  store %S undef, %S* %src
141  %2 = load i32, i32* %dstidptr
142  %dstindex = or i32 %2, 1
143  %dst2 = getelementptr %S , %S* %dst, i32 %dstindex
144  store %S %1, %S* %dst2
145  ret void
146}
147
148define void @throwing_call(%S* noalias %src, %S* %dst) {
149; CHECK-LABEL: @throwing_call(
150; CHECK-NEXT:    [[TMP1:%.*]] = load [[S:%.*]], %S* [[SRC:%.*]], align 8
151; CHECK-NEXT:    [[TMP2:%.*]] = bitcast %S* [[SRC]] to i8*
152; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[TMP2]], i8 0, i64 16, i1 false)
153; CHECK-NEXT:    call void @call() [[ATTR2:#.*]]
154; CHECK-NEXT:    store [[S]] [[TMP1]], %S* [[DST:%.*]], align 8
155; CHECK-NEXT:    ret void
156;
157  %1 = load %S, %S* %src
158  store %S zeroinitializer, %S* %src
159  call void @call() readnone
160  store %S %1, %S* %dst
161  ret void
162}
163
164declare void @call()
165