1 ; RUN: llc -mtriple=thumbv6m-eabi %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-T1
2 ; RUN: llc -mtriple=thumbv7m-eabi %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-T2
7 ; CHECK-LABEL: ldrsb_rr
8 ; CHECK: ldrsb r0, [r0, r1]
9 define i32 @ldrsb_rr(i8* %p, i32 %n) {
11 %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
12 %0 = load i8, i8* %arrayidx, align 1
13 %conv = sext i8 %0 to i32
17 ; CHECK-LABEL: ldrsh_rr
18 ; CHECK-T1: lsls r1, r1, #1
19 ; CHECK-T1: ldrsh r0, [r0, r1]
20 ; CHECK-T2: ldrsh.w r0, [r0, r1, lsl #1]
21 define i32 @ldrsh_rr(i16* %p, i32 %n) {
23 %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
24 %0 = load i16, i16* %arrayidx, align 2
25 %conv = sext i16 %0 to i32
29 ; CHECK-LABEL: ldrb_rr
30 ; CHECK: ldrb r0, [r0, r1]
31 define i32 @ldrb_rr(i8* %p, i32 %n) {
33 %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
34 %0 = load i8, i8* %arrayidx, align 1
35 %conv = zext i8 %0 to i32
39 ; CHECK-LABEL: ldrh_rr
40 ; CHECK-T1: lsls r1, r1, #1
41 ; CHECK-T1: ldrh r0, [r0, r1]
42 ; CHECK-T2: ldrh.w r0, [r0, r1, lsl #1]
43 define i32 @ldrh_rr(i16* %p, i32 %n) {
45 %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
46 %0 = load i16, i16* %arrayidx, align 2
47 %conv = zext i16 %0 to i32
52 ; CHECK-T1: lsls r1, r1, #2
53 ; CHECK-T1: ldr r0, [r0, r1]
54 ; CHECK-T2: ldr.w r0, [r0, r1, lsl #2]
55 define i32 @ldr_rr(i32* %p, i32 %n) {
57 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %n
58 %0 = load i32, i32* %arrayidx, align 4
62 ; CHECK-LABEL: strb_rr
63 ; CHECK: strb r2, [r0, r1]
64 define void @strb_rr(i8* %p, i32 %n, i32 %x) {
66 %conv = trunc i32 %x to i8
67 %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
68 store i8 %conv, i8* %arrayidx, align 1
72 ; CHECK-LABEL: strh_rr
73 ; CHECK-T1: lsls r1, r1, #1
74 ; CHECK-T1: strh r2, [r0, r1]
75 ; CHECK-T2: strh.w r2, [r0, r1, lsl #1]
76 define void @strh_rr(i16* %p, i32 %n, i32 %x) {
78 %conv = trunc i32 %x to i16
79 %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
80 store i16 %conv, i16* %arrayidx, align 2
85 ; CHECK-T1: lsls r1, r1, #2
86 ; CHECK-T1: str r2, [r0, r1]
87 ; CHECK-T2: str.w r2, [r0, r1, lsl #2]
88 define void @str_rr(i32* %p, i32 %n, i32 %x) {
90 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %n
91 store i32 %x, i32* %arrayidx, align 4
96 ; Immediate offset of zero
98 ; CHECK-LABEL: ldrsb_ri_zero
99 ; CHECK-T1: ldrb r0, [r0]
100 ; CHECK-T1: sxtb r0, r0
101 ; CHECK-T2: ldrsb.w r0, [r0]
102 define i32 @ldrsb_ri_zero(i8* %p) {
104 %0 = load i8, i8* %p, align 1
105 %conv = sext i8 %0 to i32
109 ; CHECK-LABEL: ldrsh_ri_zero
110 ; CHECK-T1: ldrh r0, [r0]
111 ; CHECK-T1: sxth r0, r0
112 ; CHECK-T2: ldrsh.w r0, [r0]
113 define i32 @ldrsh_ri_zero(i16* %p) {
115 %0 = load i16, i16* %p, align 2
116 %conv = sext i16 %0 to i32
120 ; CHECK-LABEL: ldrb_ri_zero
121 ; CHECK: ldrb r0, [r0]
122 define i32 @ldrb_ri_zero(i8* %p) {
124 %0 = load i8, i8* %p, align 1
125 %conv = zext i8 %0 to i32
129 ; CHECK-LABEL: ldrh_ri_zero
130 ; CHECK: ldrh r0, [r0]
131 define i32 @ldrh_ri_zero(i16* %p) {
133 %0 = load i16, i16* %p, align 2
134 %conv = zext i16 %0 to i32
138 ; CHECK-LABEL: ldr_ri_zero
139 ; CHECK: ldr r0, [r0]
140 define i32 @ldr_ri_zero(i32* %p) {
142 %0 = load i32, i32* %p, align 4
146 ; CHECK-LABEL: strb_ri_zero
147 ; CHECK: strb r1, [r0]
148 define void @strb_ri_zero(i8* %p, i32 %x) {
150 %conv = trunc i32 %x to i8
151 store i8 %conv, i8* %p, align 1
155 ; CHECK-LABEL: strh_ri_zero
156 ; CHECK: strh r1, [r0]
157 define void @strh_ri_zero(i16* %p, i32 %x) {
159 %conv = trunc i32 %x to i16
160 store i16 %conv, i16* %p, align 2
164 ; CHECK-LABEL: str_ri_zero
165 ; CHECK: str r1, [r0]
166 define void @str_ri_zero(i32* %p, i32 %x) {
168 store i32 %x, i32* %p, align 4
173 ; Maximum Thumb-1 immediate offset
175 ; CHECK-LABEL: ldrsb_ri_t1_max
176 ; CHECK-T1: movs r1, #31
177 ; CHECK-T1: ldrsb r0, [r0, r1]
178 ; CHECK-T2: ldrsb.w r0, [r0, #31]
179 define i32 @ldrsb_ri_t1_max(i8* %p) {
181 %arrayidx = getelementptr inbounds i8, i8* %p, i32 31
182 %0 = load i8, i8* %arrayidx, align 1
183 %conv = sext i8 %0 to i32
187 ; CHECK-LABEL: ldrsh_ri_t1_max
188 ; CHECK-T1: movs r1, #62
189 ; CHECK-T1: ldrsh r0, [r0, r1]
190 ; CHECK-T2: ldrsh.w r0, [r0, #62]
191 define i32 @ldrsh_ri_t1_max(i16* %p) {
193 %arrayidx = getelementptr inbounds i16, i16* %p, i32 31
194 %0 = load i16, i16* %arrayidx, align 2
195 %conv = sext i16 %0 to i32
199 ; CHECK-LABEL: ldrb_ri_t1_max
200 ; CHECK: ldrb r0, [r0, #31]
201 define i32 @ldrb_ri_t1_max(i8* %p) {
203 %arrayidx = getelementptr inbounds i8, i8* %p, i32 31
204 %0 = load i8, i8* %arrayidx, align 1
205 %conv = zext i8 %0 to i32
209 ; CHECK-LABEL: ldrh_ri_t1_max
210 ; CHECK: ldrh r0, [r0, #62]
211 define i32 @ldrh_ri_t1_max(i16* %p) {
213 %arrayidx = getelementptr inbounds i16, i16* %p, i32 31
214 %0 = load i16, i16* %arrayidx, align 2
215 %conv = zext i16 %0 to i32
219 ; CHECK-LABEL: ldr_ri_t1_max
220 ; CHECK: ldr r0, [r0, #124]
221 define i32 @ldr_ri_t1_max(i32* %p) {
223 %arrayidx = getelementptr inbounds i32, i32* %p, i32 31
224 %0 = load i32, i32* %arrayidx, align 4
228 ; CHECK-LABEL: strb_ri_t1_max
229 ; CHECK: strb r1, [r0, #31]
230 define void @strb_ri_t1_max(i8* %p, i32 %x) {
232 %conv = trunc i32 %x to i8
233 %arrayidx = getelementptr inbounds i8, i8* %p, i32 31
234 store i8 %conv, i8* %arrayidx, align 1
238 ; CHECK-LABEL: strh_ri_t1_max
239 ; CHECK: strh r1, [r0, #62]
240 define void @strh_ri_t1_max(i16* %p, i32 %x) {
242 %conv = trunc i32 %x to i16
243 %arrayidx = getelementptr inbounds i16, i16* %p, i32 31
244 store i16 %conv, i16* %arrayidx, align 2
248 ; CHECK-LABEL: str_ri_t1_max
249 ; CHECK: str r1, [r0, #124]
250 define void @str_ri_t1_max(i32* %p, i32 %x) {
252 %arrayidx = getelementptr inbounds i32, i32* %p, i32 31
253 store i32 %x, i32* %arrayidx, align 4
258 ; One past maximum Thumb-1 immediate offset
260 ; CHECK-LABEL: ldrsb_ri_t1_too_big
261 ; CHECK-T1: movs r1, #32
262 ; CHECK-T1: ldrsb r0, [r0, r1]
263 ; CHECK-T2: ldrsb.w r0, [r0, #32]
264 define i32 @ldrsb_ri_t1_too_big(i8* %p) {
266 %arrayidx = getelementptr inbounds i8, i8* %p, i32 32
267 %0 = load i8, i8* %arrayidx, align 1
268 %conv = sext i8 %0 to i32
272 ; CHECK-LABEL: ldrsh_ri_t1_too_big
273 ; CHECK-T1: movs r1, #64
274 ; CHECK-T1: ldrsh r0, [r0, r1]
275 ; CHECK-T2: ldrsh.w r0, [r0, #64]
276 define i32 @ldrsh_ri_t1_too_big(i16* %p) {
278 %arrayidx = getelementptr inbounds i16, i16* %p, i32 32
279 %0 = load i16, i16* %arrayidx, align 2
280 %conv = sext i16 %0 to i32
284 ; CHECK-LABEL: ldrb_ri_t1_too_big
285 ; CHECK-T1: movs r1, #32
286 ; CHECK-T1: ldrb r0, [r0, r1]
287 ; CHECK-T2: ldrb.w r0, [r0, #32]
288 define i32 @ldrb_ri_t1_too_big(i8* %p) {
290 %arrayidx = getelementptr inbounds i8, i8* %p, i32 32
291 %0 = load i8, i8* %arrayidx, align 1
292 %conv = zext i8 %0 to i32
296 ; CHECK-LABEL: ldrh_ri_t1_too_big
297 ; CHECK-T1: movs r1, #64
298 ; CHECK-T1: ldrh r0, [r0, r1]
299 ; CHECK-T2: ldrh.w r0, [r0, #64]
300 define i32 @ldrh_ri_t1_too_big(i16* %p) {
302 %arrayidx = getelementptr inbounds i16, i16* %p, i32 32
303 %0 = load i16, i16* %arrayidx, align 2
304 %conv = zext i16 %0 to i32
308 ; CHECK-LABEL: ldr_ri_t1_too_big
309 ; CHECK-T1: movs r1, #128
310 ; CHECK-T1: ldr r0, [r0, r1]
311 ; CHECK-T2: ldr.w r0, [r0, #128]
312 define i32 @ldr_ri_t1_too_big(i32* %p) {
314 %arrayidx = getelementptr inbounds i32, i32* %p, i32 32
315 %0 = load i32, i32* %arrayidx, align 4
319 ; CHECK-LABEL: strb_ri_t1_too_big
320 ; CHECK-T1: movs r2, #32
321 ; CHECK-T1: strb r1, [r0, r2]
322 ; CHECK-T2: strb.w r1, [r0, #32]
323 define void @strb_ri_t1_too_big(i8* %p, i32 %x) {
325 %conv = trunc i32 %x to i8
326 %arrayidx = getelementptr inbounds i8, i8* %p, i32 32
327 store i8 %conv, i8* %arrayidx, align 1
331 ; CHECK-LABEL: strh_ri_t1_too_big
332 ; CHECK-T1: movs r2, #64
333 ; CHECK-T1: strh r1, [r0, r2]
334 ; CHECK-T2: strh.w r1, [r0, #64]
335 define void @strh_ri_t1_too_big(i16* %p, i32 %x) {
337 %conv = trunc i32 %x to i16
338 %arrayidx = getelementptr inbounds i16, i16* %p, i32 32
339 store i16 %conv, i16* %arrayidx, align 2
343 ; CHECK-LABEL: str_ri_t1_too_big
344 ; CHECK-T1: movs r2, #128
345 ; CHECK-T1: str r1, [r0, r2]
346 ; CHECK-T2: str.w r1, [r0, #128]
347 define void @str_ri_t1_too_big(i32* %p, i32 %x) {
349 %arrayidx = getelementptr inbounds i32, i32* %p, i32 32
350 store i32 %x, i32* %arrayidx, align 4
355 ; Maximum Thumb-2 immediate offset
357 ; CHECK-LABEL: ldrsb_ri_t2_max
358 ; CHECK-T1: ldr r1, .LCP
359 ; CHECK-T1: ldrsb r0, [r0, r1]
360 ; CHECK-T2: ldrsb.w r0, [r0, #4095]
361 define i32 @ldrsb_ri_t2_max(i8* %p) {
363 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
364 %0 = load i8, i8* %add.ptr, align 1
365 %conv = sext i8 %0 to i32
369 ; CHECK-LABEL: ldrsh_ri_t2_max
370 ; CHECK-T1: ldr r1, .LCP
371 ; CHECK-T1: ldrsh r0, [r0, r1]
372 ; CHECK-T2: ldrsh.w r0, [r0, #4095]
373 define i32 @ldrsh_ri_t2_max(i8* %p) {
375 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
376 %0 = bitcast i8* %add.ptr to i16*
377 %1 = load i16, i16* %0, align 2
378 %conv = sext i16 %1 to i32
382 ; CHECK-LABEL: ldrb_ri_t2_max
383 ; CHECK-T1: ldr r1, .LCP
384 ; CHECK-T1: ldrb r0, [r0, r1]
385 ; CHECK-T2: ldrb.w r0, [r0, #4095]
386 define i32 @ldrb_ri_t2_max(i8* %p) {
388 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
389 %0 = load i8, i8* %add.ptr, align 1
390 %conv = zext i8 %0 to i32
394 ; CHECK-LABEL: ldrh_ri_t2_max
395 ; CHECK-T1: ldr r1, .LCP
396 ; CHECK-T1: ldrh r0, [r0, r1]
397 ; CHECK-T2: ldrh.w r0, [r0, #4095]
398 define i32 @ldrh_ri_t2_max(i8* %p) {
400 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
401 %0 = bitcast i8* %add.ptr to i16*
402 %1 = load i16, i16* %0, align 2
403 %conv = zext i16 %1 to i32
407 ; CHECK-LABEL: ldr_ri_t2_max
408 ; CHECK-T1: ldr r1, .LCP
409 ; CHECK-T1: ldr r0, [r0, r1]
410 ; CHECK-T2: ldr.w r0, [r0, #4095]
411 define i32 @ldr_ri_t2_max(i8* %p) {
413 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
414 %0 = bitcast i8* %add.ptr to i32*
415 %1 = load i32, i32* %0, align 4
419 ; CHECK-LABEL: strb_ri_t2_max
420 ; CHECK-T1: ldr r2, .LCP
421 ; CHECK-T1: strb r1, [r0, r2]
422 ; CHECK-T2: strb.w r1, [r0, #4095]
423 define void @strb_ri_t2_max(i8* %p, i32 %x) {
425 %conv = trunc i32 %x to i8
426 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
427 store i8 %conv, i8* %add.ptr, align 1
431 ; CHECK-LABEL: strh_ri_t2_max
432 ; CHECK-T1: ldr r2, .LCP
433 ; CHECK-T1: strh r1, [r0, r2]
434 ; CHECK-T2: strh.w r1, [r0, #4095]
435 define void @strh_ri_t2_max(i8* %p, i32 %x) {
437 %conv = trunc i32 %x to i16
438 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
439 %0 = bitcast i8* %add.ptr to i16*
440 store i16 %conv, i16* %0, align 2
444 ; CHECK-LABEL: str_ri_t2_max
445 ; CHECK-T1: ldr r2, .LCP
446 ; CHECK-T1: str r1, [r0, r2]
447 ; CHECK-T2: str.w r1, [r0, #4095]
448 define void @str_ri_t2_max(i8* %p, i32 %x) {
450 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
451 %0 = bitcast i8* %add.ptr to i32*
452 store i32 %x, i32* %0, align 4
457 ; One past maximum Thumb-2 immediate offset
459 ; CHECK-LABEL: ldrsb_ri_t2_too_big
460 ; CHECK-T1: movs r1, #1
461 ; CHECK-T1: lsls r1, r1, #12
462 ; CHECK-T2: mov.w r1, #4096
463 ; CHECK: ldrsb r0, [r0, r1]
464 define i32 @ldrsb_ri_t2_too_big(i8* %p) {
466 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
467 %0 = load i8, i8* %add.ptr, align 1
468 %conv = sext i8 %0 to i32
472 ; CHECK-LABEL: ldrsh_ri_t2_too_big
473 ; CHECK-T1: movs r1, #1
474 ; CHECK-T1: lsls r1, r1, #12
475 ; CHECK-T2: mov.w r1, #4096
476 ; CHECK: ldrsh r0, [r0, r1]
477 define i32 @ldrsh_ri_t2_too_big(i8* %p) {
479 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
480 %0 = bitcast i8* %add.ptr to i16*
481 %1 = load i16, i16* %0, align 2
482 %conv = sext i16 %1 to i32
486 ; CHECK-LABEL: ldrb_ri_t2_too_big
487 ; CHECK-T1: movs r1, #1
488 ; CHECK-T1: lsls r1, r1, #12
489 ; CHECK-T2: mov.w r1, #4096
490 ; CHECK: ldrb r0, [r0, r1]
491 define i32 @ldrb_ri_t2_too_big(i8* %p) {
493 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
494 %0 = load i8, i8* %add.ptr, align 1
495 %conv = zext i8 %0 to i32
499 ; CHECK-LABEL: ldrh_ri_t2_too_big
500 ; CHECK-T1: movs r1, #1
501 ; CHECK-T1: lsls r1, r1, #12
502 ; CHECK-T2: mov.w r1, #4096
503 ; CHECK: ldrh r0, [r0, r1]
504 define i32 @ldrh_ri_t2_too_big(i8* %p) {
506 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
507 %0 = bitcast i8* %add.ptr to i16*
508 %1 = load i16, i16* %0, align 2
509 %conv = zext i16 %1 to i32
513 ; CHECK-LABEL: ldr_ri_t2_too_big
514 ; CHECK-T1: movs r1, #1
515 ; CHECK-T1: lsls r1, r1, #12
516 ; CHECK-T2: mov.w r1, #4096
517 ; CHECK: ldr r0, [r0, r1]
518 define i32 @ldr_ri_t2_too_big(i8* %p) {
520 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
521 %0 = bitcast i8* %add.ptr to i32*
522 %1 = load i32, i32* %0, align 4
526 ; CHECK-LABEL: strb_ri_t2_too_big
527 ; CHECK-T1: movs r2, #1
528 ; CHECK-T1: lsls r2, r2, #12
529 ; CHECK-T2: mov.w r2, #4096
530 ; CHECK: strb r1, [r0, r2]
531 define void @strb_ri_t2_too_big(i8* %p, i32 %x) {
533 %conv = trunc i32 %x to i8
534 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
535 store i8 %conv, i8* %add.ptr, align 1
539 ; CHECK-LABEL: strh_ri_t2_too_big
540 ; CHECK-T1: movs r2, #1
541 ; CHECK-T1: lsls r2, r2, #12
542 ; CHECK-T2: mov.w r2, #4096
543 ; CHECK: strh r1, [r0, r2]
544 define void @strh_ri_t2_too_big(i8* %p, i32 %x) {
546 %conv = trunc i32 %x to i16
547 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
548 %0 = bitcast i8* %add.ptr to i16*
549 store i16 %conv, i16* %0, align 2
553 ; CHECK-LABEL: str_ri_t2_too_big
554 ; CHECK-T1: movs r2, #1
555 ; CHECK-T1: lsls r2, r2, #12
556 ; CHECK-T2: mov.w r2, #4096
557 ; CHECK: str r1, [r0, r2]
558 define void @str_ri_t2_too_big(i8* %p, i32 %x) {
560 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
561 %0 = bitcast i8* %add.ptr to i32*
562 store i32 %x, i32* %0, align 4