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