1; RUN: llc -mtriple=thumbv8m.main %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V8M
2; RUN: llc -mtriple=armv8 %s -o - | FileCheck %s --check-prefix=CHECK-V8
3
4; CHECK-LABEL: pre_inc_ldr
5; CHECK: ldr{{.*}}, [r0, #4]!
6define i32* @pre_inc_ldr(i32* %base, i32 %a) {
7  %addr = getelementptr i32, i32* %base, i32 1
8  %ld = load i32, i32* %addr
9  %addr.1 = getelementptr i32, i32* %base, i32 2
10  %res = add i32 %ld, %a
11  store i32 %res, i32* %addr.1
12  ret i32* %addr
13}
14
15; CHECK-LABEL: pre_dec_ldr
16; CHECK: ldr{{.*}}, [r0, #-4]!
17define i32* @pre_dec_ldr(i32* %base, i32 %a) {
18  %addr = getelementptr i32, i32* %base, i32 -1
19  %ld = load i32, i32* %addr
20  %addr.1 = getelementptr i32, i32* %base, i32 2
21  %res = add i32 %ld, %a
22  store i32 %res, i32* %addr.1
23  ret i32* %addr
24}
25
26; CHECK-LABEL: post_inc_ldr
27; CHECK: ldr{{.*}}, [r0], #4
28define i32* @post_inc_ldr(i32* %base, i32* %addr.2, i32 %a) {
29  %addr = getelementptr i32, i32* %base, i32 0
30  %ld = load i32, i32* %addr
31  %addr.1 = getelementptr i32, i32* %base, i32 1
32  %res = add i32 %ld, %a
33  store i32 %res, i32* %addr.2
34  ret i32* %addr.1
35}
36
37; CHECK-LABEL: post_dec_ldr
38; CHECK: ldr{{.*}}, [r0], #-4
39define i32* @post_dec_ldr(i32* %base, i32* %addr.2, i32 %a) {
40  %addr = getelementptr i32, i32* %base, i32 0
41  %ld = load i32, i32* %addr
42  %addr.1 = getelementptr i32, i32* %base, i32 -1
43  %res = add i32 %ld, %a
44  store i32 %res, i32* %addr.2
45  ret i32* %addr.1
46}
47
48; CHECK-LABEL: pre_inc_str
49; CHECK: str{{.*}}, [r0, #4]!
50define i32* @pre_inc_str(i32* %base, i32 %a, i32 %b) {
51  %addr.1 = getelementptr i32, i32* %base, i32 1
52  %res = add i32 %a, %b
53  store i32 %res, i32* %addr.1
54  ret i32* %addr.1
55}
56
57; CHECK-LABEL: pre_dec_str
58; CHECK: str{{.*}}, [r0, #-4]!
59define i32* @pre_dec_str(i32* %base, i32 %a, i32 %b) {
60  %res = add i32 %a, %b
61  %addr.1 = getelementptr i32, i32* %base, i32 -1
62  store i32 %res, i32* %addr.1
63  ret i32* %addr.1
64}
65
66; CHECK-LABEL: post_inc_str
67; CHECK: str{{.*}}, [r0], #4
68define i32* @post_inc_str(i32* %base, i32 %a, i32 %b) {
69  %addr.1 = getelementptr i32, i32* %base, i32 1
70  %res = add i32 %a, %b
71  store i32 %res, i32* %base
72  ret i32* %addr.1
73}
74
75; CHECK-LABEL: post_dec_str
76; CHECK: str{{.*}}, [r0], #-4
77define i32* @post_dec_str(i32* %base, i32 %a, i32 %b) {
78  %addr.1 = getelementptr i32, i32* %base, i32 -1
79  %res = add i32 %a, %b
80  store i32 %res, i32* %base
81  ret i32* %addr.1
82}
83
84; TODO: Generate ldrd
85; CHECK-LABEL: pre_inc_ldrd
86; CHECK: ldr{{.*}}, #4]!
87define i32* @pre_inc_ldrd(i32* %base) {
88  %addr = getelementptr i32, i32* %base, i32 1
89  %addr.1 = getelementptr i32, i32* %base, i32 2
90  %addr.2 = getelementptr i32, i32* %base, i32 3
91  %ld = load i32, i32* %addr
92  %ld.1 = load i32, i32* %addr.1
93  %res = add i32 %ld, %ld.1
94  store i32 %res, i32* %addr.2
95  ret i32* %addr
96}
97
98; TODO: Generate ldrd
99; CHECK-LABEL: pre_dec_ldrd
100; CHECK: ldr{{.*}}, #-4]!
101define i32* @pre_dec_ldrd(i32* %base) {
102  %addr = getelementptr i32, i32* %base, i32 -1
103  %addr.1 = getelementptr i32, i32* %base, i32 -2
104  %addr.2 = getelementptr i32, i32* %base, i32 -3
105  %ld = load i32, i32* %addr
106  %ld.1 = load i32, i32* %addr.1
107  %res = add i32 %ld, %ld.1
108  store i32 %res, i32* %addr.2
109  ret i32* %addr
110}
111
112; TODO: Generate post inc
113; CHECK-LABEL: post_inc_ldrd
114; CHECK-V8M: ldrd{{.*}}, [r0]
115; CHECK-V8: ldm
116; CHECK: add{{.*}}, #8
117define i32* @post_inc_ldrd(i32* %base, i32* %addr.3) {
118  %addr = getelementptr i32, i32* %base, i32 0
119  %ld = load i32, i32* %addr
120  %addr.1 = getelementptr i32, i32* %base, i32 1
121  %ld.1 = load i32, i32* %addr.1
122  %addr.2 = getelementptr i32, i32* %base, i32 2
123  %res = add i32 %ld, %ld.1
124  store i32 %res, i32* %addr.3
125  ret i32* %addr.2
126}
127
128; CHECK-LABEL: pre_inc_str_multi
129; CHECK: str{{.*}}, #8]!
130define i32* @pre_inc_str_multi(i32* %base) {
131  %addr = getelementptr i32, i32* %base, i32 0
132  %addr.1 = getelementptr i32, i32* %base, i32 1
133  %ld = load i32, i32* %addr
134  %ld.1 = load i32, i32* %addr.1
135  %res = add i32 %ld, %ld.1
136  %addr.2 = getelementptr i32, i32* %base, i32 2
137  store i32 %res, i32* %addr.2
138  ret i32* %addr.2
139}
140
141; CHECK-LABEL: pre_dec_str_multi
142; CHECK: str{{.*}}, #-4]!
143define i32* @pre_dec_str_multi(i32* %base) {
144  %addr = getelementptr i32, i32* %base, i32 0
145  %addr.1 = getelementptr i32, i32* %base, i32 1
146  %ld = load i32, i32* %addr
147  %ld.1 = load i32, i32* %addr.1
148  %res = add i32 %ld, %ld.1
149  %addr.2 = getelementptr i32, i32* %base, i32 -1
150  store i32 %res, i32* %addr.2
151  ret i32* %addr.2
152}
153
154; CHECK-LABEL: illegal_pre_inc_store_1
155; CHECK-NOT: str{{.*}} ]!
156define i32* @illegal_pre_inc_store_1(i32* %base) {
157entry:
158  %ptr.to.use = getelementptr i32, i32* %base, i32 2
159  %ptr.to.store = ptrtoint i32* %base to i32
160  store i32 %ptr.to.store, i32* %ptr.to.use, align 4
161  ret i32* %ptr.to.use
162}
163
164; TODO: The mov should be unecessary
165; CHECK-LABEL: legal_pre_inc_store_needs_copy_1
166; CHECK: add{{.*}}, #8
167; CHECK-NOT: str{{.*}}]!
168; CHECK: mov
169define i32* @legal_pre_inc_store_needs_copy_1(i32* %base) {
170entry:
171  %ptr.to.use = getelementptr i32, i32* %base, i32 2
172  %ptr.to.store = ptrtoint i32* %ptr.to.use to i32
173  store i32 %ptr.to.store, i32* %ptr.to.use, align 4
174  ret i32* %ptr.to.use
175}
176
177; CHECK-LABEL: legal_pre_inc_store_needs_copy_2
178; CHECK-NOT: mov
179; CHECK-NOT: str{{.*}}]!
180define i32* @legal_pre_inc_store_needs_copy_2(i32 %base) {
181entry:
182  %ptr = inttoptr i32 %base to i32*
183  %ptr.to.use = getelementptr i32, i32* %ptr, i32 2
184  store i32 %base, i32* %ptr.to.use, align 4
185  ret i32* %ptr.to.use
186}
187