aboutsummaryrefslogtreecommitdiff
path: root/llvm/test/CodeGen/ARM/execute-only-split-offset.ll
blob: c4ee3189dd772363742d8b5ee961afb3dd546789 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
; RUN: llc -mtriple=thumbv8m.base-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefixes=CHECK,CHECK-MOVW %s
; RUN: llc -mtriple=thumbv6m-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefixes=CHECK,CHECK-NOMOVW %s

; Largest offset that fits into sp-relative ldr
; CHECK-LABEL: ldr_range_end:
; CHECK: ldr {{r[0-9]+}}, [sp, #1020]
define i32 @ldr_range_end() {
entry:
  %var = alloca i32, align 4
  %arr = alloca [1020 x i8], align 4
  %0 = load i32, ptr %var, align 4
  ret i32 %0
}

; Smallest offset that fits into add+ldr
; CHECK-LABEL: add_ldr_range_start:
; CHECK:      add [[REG:r[0-9]+]], sp, #900
; CHECK-NEXT: ldr {{r[0-9]+}}, [[[REG]], #124]
define i32 @add_ldr_range_start() {
entry:
  %var = alloca i32, align 4
  %arr = alloca [1024 x i8], align 4
  %0 = load i32, ptr %var, align 4
  ret i32 %0
}

; Largest offset that fits into add+ldr
; CHECK-LABEL: add_ldr_range_end:
; CHECK:      add [[REG:r[0-9]+]], sp, #1020
; CHECK-NEXT: ldr {{r[0-9]+}}, [[[REG]], #124]
define i32 @add_ldr_range_end() {
entry:
  %var = alloca i32, align 4
  %arr = alloca [1144 x i8], align 4
  %0 = load i32, ptr %var, align 4
  ret i32 %0
}

; Smallest offset where we start using mov32. If we don't have movw then using
; an ldr offset means we save an add.
; CHECK-LABEL: mov32_range_start:
; CHECK-MOVW:        movw [[REG:r[0-9]+]], #1148
; CHECK-NOMOVW:      movs [[REG:r[0-9]+]], #4
; CHECK-NOMOVW-NEXT: lsls [[REG]], [[REG]], #8
; CHECK-NEXT:        add [[REG]], sp
; CHECK-MOVW-NEXT:   ldr {{r[0-9]+}}, [[[REG]]]
; CHECK-NOMOVW-NEXT: ldr {{r[0-9]+}}, [[[REG]], #124]
define i32 @mov32_range_start() {
entry:
  %var = alloca i32, align 4
  %arr = alloca [1148 x i8], align 4
  %0 = load i32, ptr %var, align 4
  ret i32 %0
}

; Here using an ldr offset doesn't save an add so we shouldn't do it.
; CHECK-LABEL: mov32_range_next:
; CHECK-MOVW:        movw [[REG:r[0-9]+]], #1152
; CHECK-NOMOVW:      movs [[REG:r[0-9]+]], #4
; CHECK-NOMOVW-NEXT: lsls [[REG]], [[REG]], #8
; CHECK-NOMOVW-NEXT: adds [[REG]], #128
; CHECK-NEXT:        add [[REG]], sp
; CHECK-NEXT:        ldr {{r[0-9]+}}, [[[REG]]]
define i32 @mov32_range_next() {
entry:
  %var = alloca i32, align 4
  %arr = alloca [1152 x i8], align 4
  %0 = load i32, ptr %var, align 4
  ret i32 %0
}

; Smallest offset where using an ldr offset prevents needing a movt or lsl+add
; CHECK-LABEL: can_clear_top_byte_start:
; CHECK:             add sp, {{r[0-9]+}}
; CHECK-MOVW:        movw [[REG:r[0-9]+]], #65412
; CHECK-NOMOVW:      movs [[REG:r[0-9]+]], #255
; CHECK-NOMOVW-NEXT: lsls [[REG:r[0-9]+]], [[REG:r[0-9]+]], #8
; CHECK-NOMOVW-NEXT: adds [[REG:r[0-9]+]], #132
; CHECK-NEXT:        add [[REG]], sp
; CHECK-NEXT:        ldr {{r[0-9]+}}, [[[REG]], #124]
define i32 @can_clear_top_byte_start() {
entry:
  %var = alloca i32, align 4
  %arr = alloca [65536 x i8], align 4
  %0 = load i32, ptr %var, align 4
  ret i32 %0
}

; Largest offset where using an ldr offset prevents needing a movt or lsl+add
; CHECK-LABEL: can_clear_top_byte_end:
; CHECK:             add sp, {{r[0-9]+}}
; CHECK-MOVW:        movw [[REG:r[0-9]+]], #65532
; CHECK-NOMOVW:      movs [[REG:r[0-9]+]], #255
; CHECK-NOMOVW-NEXT: lsls [[REG:r[0-9]+]], [[REG:r[0-9]+]], #8
; CHECK-NOMOVW-NEXT: adds [[REG:r[0-9]+]], #252
; CHECK-NEXT:        add [[REG]], sp
; CHECK-NEXT:        ldr {{r[0-9]+}}, [[[REG]], #124]
define i32 @can_clear_top_byte_end() {
entry:
  %var = alloca i32, align 4
  %arr = alloca [65656 x i8], align 4
  %0 = load i32, ptr %var, align 4
  ret i32 %0
}

; Smallest offset where using an ldr offset doesn't clear the top byte, though
; we can use an ldr offset if not using movt to save an add of the low byte.
; CHECK-LABEL: cant_clear_top_byte_start:
; CHECK:             add sp, {{r[0-9]+}}
; CHECK-MOVW:        movw [[REG:r[0-9]+]], #124
; CHECK-MOVW-NEXT:   movt [[REG:r[0-9]+]], #1
; CHECK-NOMOVW:      movs [[REG:r[0-9]+]], #1
; CHECK-NOMOVW-NEXT: lsls [[REG:r[0-9]+]], [[REG:r[0-9]+]], #16
; CHECK-NEXT:        add [[REG]], sp
; CHECK-MOVW-NEXT:   ldr {{r[0-9]+}}, [[[REG]]]
; CHECK-NOMOVW-NEXT: ldr {{r[0-9]+}}, [[[REG]], #124]
define i32 @cant_clear_top_byte_start() {
entry:
  %var = alloca i32, align 4
  %arr = alloca [65660 x i8], align 4
  %0 = load i32, ptr %var, align 4
  ret i32 %0
}

; An ldr offset doesn't help for anything, so we shouldn't do it.
; CHECK-LABEL: cant_clear_top_byte_next:
; CHECK:             add sp, {{r[0-9]+}}
; CHECK-MOVW:        movw [[REG:r[0-9]+]], #128
; CHECK-MOVW:        movt [[REG:r[0-9]+]], #1
; CHECK-NOMOVW:      movs [[REG:r[0-9]+]], #1
; CHECK-NOMOVW-NEXT: lsls [[REG:r[0-9]+]], [[REG:r[0-9]+]], #16
; CHECK-NOMOVW-NEXT: adds [[REG:r[0-9]+]], #128
; CHECK-NEXT:        add [[REG]], sp
; CHECK-NEXT:        ldr {{r[0-9]+}}, [[[REG]]]
define i32 @cant_clear_top_byte_next() {
entry:
  %var = alloca i32, align 4
  %arr = alloca [65664 x i8], align 4
  %0 = load i32, ptr %var, align 4
  ret i32 %0
}