• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; Tests basics and corner cases of arm32 sandboxing, using -Om1 in the hope that
2; the output will remain stable.  When packing bundles, we try to limit to a few
3; instructions with well known sizes and minimal use of registers and stack
4; slots in the lowering sequence.
5
6; REQUIRES: allow_dump, target_ARM32
7; RUN: %p2i -i %s --sandbox --filetype=asm --target=arm32 --assemble \
8; RUN:   --disassemble --args -Om1 -allow-externally-defined-symbols \
9; RUN:   -ffunction-sections -reg-use r0,r1,r3 | FileCheck %s
10
11declare void @call_target()
12declare void @call_target1(i32 %arg0)
13declare void @call_target2(i32 %arg0, i32 %arg1)
14declare void @call_target3(i32 %arg0, i32 %arg1, i32 %arg2)
15@global_short = internal global [2 x i8] zeroinitializer
16
17; A direct call sequence uses the right mask and register-call sequence.
18define internal void @test_direct_call() {
19entry:
20  call void @call_target()
21  ; bundle aigned.
22  ret void
23}
24
25; CHECK-LABEL:<test_direct_call>:
26;             Search for bundle alignment of first call.
27; CHECK:      {{[0-9a-f]*}}c: {{.*}} bl {{.*}} call_target
28
29; Same as above, but force bundle padding by adding three (branch) instruction
30; before the tested call.
31define internal void @test_direct_call_with_padding_1() {
32entry:
33  call void @call_target()
34  ; bundle aigned.
35
36  br label %next1 ; add 1 inst.
37next1:
38  br label %next2 ; add 1 inst.
39next2:
40  call void @call_target()
41  ret void
42}
43; CHECK-LABEL:<test_direct_call_with_padding_1>:
44;             Search for bundle alignment of first call.
45; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
46; CHECK-NEXT: b
47; CHECK-NEXT: b
48; CHECK-NEXT: nop
49; CHECK-NEXT: bl {{.*}} call_target
50; CHECK-NEXT: {{[0-9a-f]*}}0:
51
52; Same as above, but force bundle padding by adding two (branch) instruction
53; before the tested call.
54define internal void @test_direct_call_with_padding_2() {
55entry:
56  call void @call_target()
57  ; bundle aigned.
58
59  br label %next1 ; add 1 inst.
60next1:
61  call void @call_target()
62  ret void
63}
64
65; CHECK-LABEL:<test_direct_call_with_padding_2>:
66;             Search for bundle alignment of first call.
67; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
68; CHECK-NEXT: b
69; CHECK-NEXT: nop
70; CHECK-NEXT: nop
71; CHECK-NEXT: bl {{.*}} call_target
72; CHECK-NEXT: {{[0-9a-f]*}}0:
73
74; Same as above, but force bundle padding by adding single (branch) instruction
75; before the tested call.
76define internal void @test_direct_call_with_padding_3() {
77entry:
78  call void @call_target()
79  ; bundle aigned.
80
81  call void @call_target()
82  ret void
83}
84
85; CHECK-LABEL:<test_direct_call_with_padding_3>:
86;             Search for bundle alignment of first call.
87; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
88; CHECK-NEXT: nop
89; CHECK-NEXT: nop
90; CHECK-NEXT: nop
91; CHECK-NEXT: bl {{.*}} call_target
92; CHECK-NEXT: {{[0-9a-f]*}}0:
93
94; An indirect call sequence uses the right mask and register-call sequence.
95define internal void @test_indirect_call(i32 %target) {
96entry:
97  %__1 = inttoptr i32 %target to void ()*
98  call void @call_target();
99  ; bundle aigned.
100
101  br label %next ; add 1 inst.
102next:
103  call void %__1() ; requires 3 insts.
104  ret void
105}
106
107; CHECK-LABEL:<test_indirect_call>:
108;             Search for bundle alignment of first call.
109; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
110; CHECK-NEXT: b
111; CHECK-NEXT: ldr
112; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f
113; CHECK-NEXT: blx [[REG]]
114; CHECK-NEXT: {{[0-9]+}}0:
115
116; An indirect call sequence uses the right mask and register-call sequence.
117; Forces bundling before the tested call.
118define internal void @test_indirect_call_with_padding_1(i32 %target) {
119entry:
120  %__1 = inttoptr i32 %target to void ()*
121  call void @call_target();
122  ; bundle aigned.
123  call void %__1() ; requires 3 insts.
124  ret void
125}
126
127; CHECK-LABEL: <test_indirect_call_with_padding_1>:
128;              Search for bundle alignment of first call.
129; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
130; CHECK-NEXT: ldr
131; CHECK-NEXT: nop
132; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f
133; CHECK-NEXT: blx [[REG]]
134; CHECK-NEXT: {{[0-9]+}}0:
135
136; An indirect call sequence uses the right mask and register-call sequence.
137; Forces bundling by adding three (branch) instructions befor the tested call.
138define internal void @test_indirect_call_with_padding_2(i32 %target) {
139entry:
140  %__1 = inttoptr i32 %target to void ()*
141  call void @call_target();
142  ; bundle aigned.
143
144  br label %next1 ; add 1 inst.
145next1:
146  br label %next2 ; add 1 inst.
147next2:
148  br label %next3 ; add 1 inst.
149next3:
150  call void %__1() ; requires 3 insts.
151  ret void
152}
153
154; CHECK-LABEL: <test_indirect_call_with_padding_2>:
155;              Search for bundle alignment of first call.
156; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
157; CHECK-NEXT: b
158; CHECK-NEXT: b
159; CHECK-NEXT: b
160; CHECK-NEXT: ldr
161; CHECK-NEXT: nop
162; CHECK-NEXT: nop
163; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f
164; CHECK-NEXT: blx [[REG]]
165; CHECK-NEXT: {{[0-9]+}}0:
166
167; An indirect call sequence uses the right mask and register-call sequence.
168; Forces bundling by adding two (branch) instructions befor the tested call.
169define internal void @test_indirect_call_with_padding_3(i32 %target) {
170entry:
171  %__1 = inttoptr i32 %target to void ()*
172  call void @call_target();
173  ; bundle aigned.
174
175  br label %next1 ; add 1 inst
176next1:
177  br label %next2 ; add 1 inst
178next2:
179  call void %__1() ; requires 3 insts.
180  ret void
181}
182; CHECK-LABEL: <test_indirect_call_with_padding_3>:
183;              Search for bundle alignment of first call.
184; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
185; CHECK-NEXT: b
186; CHECK-NEXT: b
187; CHECK-NEXT: ldr
188; CHECK-NEXT: nop
189; CHECK-NEXT: nop
190; CHECK-NEXT: nop
191; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f
192; CHECK-NEXT: blx [[REG]]
193; CHECK-NEXT: {{[0-9]+}}0:
194
195; A return sequences uses the right pop / mask / jmp sequence.
196define internal void @test_ret() {
197entry:
198  call void @call_target()
199  ; Bundle boundary.
200  br label %next ; add 1 inst.
201next:
202  ret void
203}
204; CHECK-LABEL:<test_ret>:
205;             Search for bundle alignment of first call.
206; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
207; CHECK-NEXT: b
208; CHECK-NEXT: add sp, sp
209; CHECK-NEXT: bic sp, sp, {{.+}} ; 0xc0000000
210; CHECK-NEXT: pop {lr}
211; CHECK-NEXT: {{[0-9a-f]*}}0: {{.+}} bic lr, lr, {{.+}} ; 0xc000000f
212; CHECK-NEXT: bx lr
213
214; A return sequence with padding for bundle lock.
215define internal void @test_ret_with_padding() {
216  call void @call_target()
217  ; Bundle boundary.
218  ret void
219}
220
221; CHECK-LABEL:<test_ret_with_padding>:
222;             Search for bundle alignment of first call.
223; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
224; CHECK-NEXT: add sp, sp
225; CHECK-NEXT: bic sp, sp, {{.+}} ; 0xc0000000
226; CHECK-NEXT: pop {lr}
227; CHECK-NEXT: nop
228; CHECK-NEXT: {{[0-9a-f]*}}0: {{.+}} bic lr, lr, {{.+}} ; 0xc000000f
229; CHECK-NEXT: bx lr
230
231; Store without bundle padding.
232define internal void @test_store() {
233entry:
234  call void @call_target()
235  ; Bundle boundary
236  store i16 1, i16* undef, align 1   ; 3 insts + bic.
237  ret void
238}
239
240; CHECK-LABEL: test_store
241;             Search for call at end of bundle.
242; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
243; CHECK-NEXT: mov [[REG:r[0-9]]], #0
244; CHECK-NEXT: mov
245; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000
246; CHECK-NEXT: strh r{{.+}}[[REG]]
247
248; Store with bundle padding. Force padding by adding a single branch
249; instruction.
250define internal void @test_store_with_padding() {
251entry:
252  call void @call_target()
253  ; bundle boundary
254  br label %next ; add 1 inst.
255next:
256  store i16 0, i16* undef, align 1   ; 3 insts
257  ret void
258}
259; CHECK-LABEL: test_store_with_padding
260;             Search for call at end of bundle.
261; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
262; CHECK-NEXT: b
263; CHECK-NEXT: mov [[REG:r[0-9]]], #0
264; CHECK-NEXT: mov
265; CHECK-NEXT: nop
266; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000
267; CHECK-NEXT: strh r{{.+}}[[REG]]
268
269
270; Store without bundle padding.
271define internal i32 @test_load() {
272entry:
273  call void @call_target()
274  ; Bundle boundary
275  %v = load i32, i32* undef, align 1 ; 4 insts, bundling middle 2.
276  ret i32 %v
277}
278
279; CHECK-LABEL: test_load
280;             Search for call at end of bundle.
281; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
282; CHECK-NEXT: mov [[REG:r[0-9]]], #0
283; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000
284; CHECK-NEXT: ldr r{{.+}}[[REG]]
285
286; Store with bundle padding.
287define internal i32 @test_load_with_padding() {
288entry:
289  call void @call_target()
290  ; Bundle boundary
291  br label %next1 ; add 1 inst.
292next1:
293  br label %next2 ; add 1 inst.
294next2:
295  %v = load i32, i32* undef, align 1 ; 4 insts, bundling middle 2.
296  ret i32 %v
297}
298
299; CHECK-LABEL: test_load_with_padding
300;             Search for call at end of bundle.
301; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
302; CHECK-NEXT: b
303; CHECK-NEXT: b
304; CHECK-NEXT: mov [[REG:r[0-9]]], #0
305; CHECK-NEXT: nop
306; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000
307; CHECK-NEXT: ldr r{{.+}}[[REG]]
308