1# RUN: llc -run-pass implicit-null-checks -mtriple=x86_64-apple-macosx -o - %s | FileCheck %s
2
3--- |
4  target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
5  target triple = "x86_64-apple-macosx"
6
7  ;; Positive test
8  define i32 @imp_null_check_with_bitwise_op_0(i32* %x, i32 %val) {
9  entry:
10    br i1 undef, label %is_null, label %not_null, !make.implicit !0
11
12  is_null:
13    ret i32 42
14
15  not_null:
16    br i1 undef, label %ret_100, label %ret_200
17
18  ret_100:
19    ret i32 100
20
21  ret_200:
22    ret i32 200
23  }
24
25  ;; Negative test.  The regalloc is such that we cannot hoist the
26  ;; instruction materializing 2200000 into %eax
27  define i32 @imp_null_check_with_bitwise_op_1(i32* %x, i32 %val, i32* %ptr) {
28  entry:
29    br i1 undef, label %is_null, label %not_null, !make.implicit !0
30
31  is_null:
32    ret i32 undef
33
34  not_null:
35    br i1 undef, label %ret_100, label %ret_200
36
37  ret_100:
38    ret i32 100
39
40  ret_200:
41    ret i32 200
42  }
43
44  ;; Negative test: IR is identical to
45  ;; @imp_null_check_with_bitwise_op_0 but MIR differs.
46  define i32 @imp_null_check_with_bitwise_op_2(i32* %x, i32 %val) {
47  entry:
48    br i1 undef, label %is_null, label %not_null, !make.implicit !0
49
50  is_null:
51    ret i32 42
52
53  not_null:
54    br i1 undef, label %ret_100, label %ret_200
55
56  ret_100:
57    ret i32 100
58
59  ret_200:
60    ret i32 200
61  }
62
63  ;; Negative test: IR is identical to
64  ;; @imp_null_check_with_bitwise_op_0 but MIR differs.
65  define i32 @imp_null_check_with_bitwise_op_3(i32* %x, i32 %val) {
66  entry:
67    br i1 undef, label %is_null, label %not_null, !make.implicit !0
68
69  is_null:
70    ret i32 42
71
72  not_null:
73    br i1 undef, label %ret_100, label %ret_200
74
75  ret_100:
76    ret i32 100
77
78  ret_200:
79    ret i32 200
80  }
81
82  ;; Positive test
83  define i32 @imp_null_check_with_bitwise_op_4(i32* %x, i32 %val) {
84  entry:
85    br i1 undef, label %is_null, label %not_null, !make.implicit !0
86
87  is_null:
88    ret i32 42
89
90  not_null:
91    br i1 undef, label %ret_100, label %ret_200
92
93  ret_100:
94    ret i32 100
95
96  ret_200:
97    ret i32 200
98  }
99
100  declare void @f() readonly
101
102  define i32 @no_hoist_across_call(i32* %ptr) {
103  entry:
104    %is_null = icmp eq i32* %ptr, null
105    br i1 %is_null, label %leave, label %stay, !make.implicit !0
106
107  stay:
108    call void @f()
109    %val = load i32, i32* %ptr
110    ret i32 %val
111
112  leave:
113    ret i32 0
114  }
115
116  define i32 @dependency_live_in_hazard(i32* %ptr, i32** %ptr2, i32* %ptr3) #0 {
117  entry:
118    %val = load i32*, i32** %ptr2
119    %ptr_is_null = icmp eq i32* %ptr, null
120    br i1 %ptr_is_null, label %is_null, label %not_null, !make.implicit !0
121
122  not_null:                                         ; preds = %entry
123    %addend = load i32, i32* %val
124    %result = load i32, i32* %ptr
125    %result.shr = lshr i32 %result, 4
126    %result.and = and i32 %result.shr, 4095
127    %result.add = add i32 %addend, %result.and
128    ret i32 %result.add
129
130  is_null:                                          ; preds = %entry
131    ret i32 0
132  }
133
134  attributes #0 = { "target-features"="+bmi,+bmi2" }
135
136  !0 = !{}
137...
138---
139name:            imp_null_check_with_bitwise_op_0
140# CHECK-LABEL: name:            imp_null_check_with_bitwise_op_0
141alignment:       4
142tracksRegLiveness: true
143liveins:
144  - { reg: '%rdi' }
145  - { reg: '%esi' }
146# CHECK:  bb.0.entry:
147# CHECK:    %eax = MOV32ri 2200000
148# CHECK-NEXT:    %eax = FAULTING_LOAD_OP %bb.3.is_null, {{[0-9]+}}, killed %eax, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
149# CHECK-NEXT:    JMP_1 %bb.1.not_null
150
151body:             |
152  bb.0.entry:
153    successors: %bb.3.is_null, %bb.1.not_null
154    liveins: %esi, %rdi
155
156    TEST64rr %rdi, %rdi, implicit-def %eflags
157    JE_1 %bb.3.is_null, implicit %eflags
158
159  bb.1.not_null:
160    successors: %bb.4.ret_100, %bb.2.ret_200
161    liveins: %esi, %rdi
162
163    %eax = MOV32ri 2200000
164    %eax = AND32rm killed %eax, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
165    CMP32rr killed %eax, killed %esi, implicit-def %eflags
166    JE_1 %bb.4.ret_100, implicit %eflags
167
168  bb.2.ret_200:
169    %eax = MOV32ri 200
170    RET 0, %eax
171
172  bb.3.is_null:
173    %eax = MOV32ri 42
174    RET 0, %eax
175
176  bb.4.ret_100:
177    %eax = MOV32ri 100
178    RET 0, %eax
179
180...
181---
182name:            imp_null_check_with_bitwise_op_1
183alignment:       4
184tracksRegLiveness: true
185liveins:
186  - { reg: '%rdi' }
187  - { reg: '%esi' }
188  - { reg: '%rdx' }
189# CHECK: bb.0.entry:
190# CHECK:    %eax = MOV32rm killed %rdx, 1, _, 0, _ :: (volatile load 4 from %ir.ptr)
191# CHECK-NEXT:    TEST64rr %rdi, %rdi, implicit-def %eflags
192# CHECK-NEXT:    JE_1 %bb.3.is_null, implicit %eflags
193
194body:             |
195  bb.0.entry:
196    successors: %bb.3.is_null, %bb.1.not_null
197    liveins: %esi, %rdi, %rdx
198
199    %eax = MOV32rm killed %rdx, 1, _, 0, _ :: (volatile load 4 from %ir.ptr)
200    TEST64rr %rdi, %rdi, implicit-def %eflags
201    JE_1 %bb.3.is_null, implicit %eflags
202
203  bb.1.not_null:
204    successors: %bb.4.ret_100, %bb.2.ret_200
205    liveins: %esi, %rdi
206
207    %eax = MOV32ri 2200000
208    %eax = AND32rm killed %eax, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
209    CMP32rr killed %eax, killed %esi, implicit-def %eflags
210    JE_1 %bb.4.ret_100, implicit %eflags
211
212  bb.2.ret_200:
213    successors: %bb.3.is_null
214
215    %eax = MOV32ri 200
216
217  bb.3.is_null:
218    liveins: %eax, %ah, %al, %ax, %bh, %bl, %bp, %bpl, %bx, %eax, %ebp, %ebx, %rax, %rbp, %rbx, %r12, %r13, %r14, %r15, %r12b, %r13b, %r14b, %r15b, %r12d, %r13d, %r14d, %r15d, %r12w, %r13w, %r14w, %r15w
219
220    RET 0, %eax
221
222  bb.4.ret_100:
223    %eax = MOV32ri 100
224    RET 0, %eax
225
226...
227---
228name:            imp_null_check_with_bitwise_op_2
229# CHECK-LABEL: name:            imp_null_check_with_bitwise_op_2
230alignment:       4
231tracksRegLiveness: true
232liveins:
233  - { reg: '%rdi' }
234  - { reg: '%esi' }
235# CHECK:  bb.0.entry:
236# CHECK:    TEST64rr %rdi, %rdi, implicit-def %eflags
237# CHECK-NEXT:    JE_1 %bb.3.is_null, implicit %eflags
238
239body:             |
240  bb.0.entry:
241    successors: %bb.3.is_null, %bb.1.not_null
242    liveins: %esi, %rdi
243
244    TEST64rr %rdi, %rdi, implicit-def %eflags
245    JE_1 %bb.3.is_null, implicit %eflags
246
247  bb.1.not_null:
248    successors: %bb.4.ret_100, %bb.2.ret_200
249    liveins: %esi, %rdi
250
251    %eax = MOV32ri 2200000
252    %eax = ADD32ri killed %eax, 100, implicit-def dead %eflags
253    %eax = AND32rm killed %eax, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
254    CMP32rr killed %eax, killed %esi, implicit-def %eflags
255    JE_1 %bb.4.ret_100, implicit %eflags
256
257  bb.2.ret_200:
258    %eax = MOV32ri 200
259    RET 0, %eax
260
261  bb.3.is_null:
262    %eax = MOV32ri 42
263    RET 0, %eax
264
265  bb.4.ret_100:
266    %eax = MOV32ri 100
267    RET 0, %eax
268
269...
270---
271name:            imp_null_check_with_bitwise_op_3
272# CHECK-LABEL: name:            imp_null_check_with_bitwise_op_3
273alignment:       4
274tracksRegLiveness: true
275liveins:
276  - { reg: '%rdi' }
277  - { reg: '%rsi' }
278# CHECK:  bb.0.entry:
279# CHECK:    TEST64rr %rdi, %rdi, implicit-def %eflags
280# CHECK-NEXT:    JE_1 %bb.3.is_null, implicit %eflags
281
282body:             |
283  bb.0.entry:
284    successors: %bb.3.is_null, %bb.1.not_null
285    liveins: %rsi, %rdi
286
287    TEST64rr %rdi, %rdi, implicit-def %eflags
288    JE_1 %bb.3.is_null, implicit %eflags
289
290  bb.1.not_null:
291    successors: %bb.4.ret_100, %bb.2.ret_200
292    liveins: %rsi, %rdi
293
294    %rdi  = MOV64ri 5000
295    %rdi = AND64rm killed %rdi, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
296    CMP64rr killed %rdi, killed %rsi, implicit-def %eflags
297    JE_1 %bb.4.ret_100, implicit %eflags
298
299  bb.2.ret_200:
300    %eax = MOV32ri 200
301    RET 0, %eax
302
303  bb.3.is_null:
304    %eax = MOV32ri 42
305    RET 0, %eax
306
307  bb.4.ret_100:
308    %eax = MOV32ri 100
309    RET 0, %eax
310
311...
312---
313name:            imp_null_check_with_bitwise_op_4
314# CHECK-LABEL: name:            imp_null_check_with_bitwise_op_4
315alignment:       4
316tracksRegLiveness: true
317liveins:
318  - { reg: '%rdi' }
319  - { reg: '%rsi' }
320# CHECK:  bb.0.entry:
321# CHECK:  %rbx = MOV64rr %rdx
322# CHECK-NEXT:  %rdi = FAULTING_LOAD_OP %bb.3.is_null, {{[0-9]+}}, killed %rbx, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
323
324body:             |
325  bb.0.entry:
326    successors: %bb.3.is_null, %bb.1.not_null
327    liveins: %rsi, %rdi, %rdx
328
329    TEST64rr %rdi, %rdi, implicit-def %eflags
330    JE_1 %bb.3.is_null, implicit %eflags
331
332  bb.1.not_null:
333    successors: %bb.4.ret_100, %bb.2.ret_200
334    liveins: %rsi, %rdi, %rdx
335
336    %rbx  = MOV64rr %rdx
337    %rdi = AND64rm killed %rbx, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
338    %rdx = MOV64ri 0
339    CMP64rr killed %rdi, killed %rsi, implicit-def %eflags
340    JE_1 %bb.4.ret_100, implicit %eflags
341
342  bb.2.ret_200:
343    %eax = MOV32ri 200
344    RET 0, %eax
345
346  bb.3.is_null:
347    %eax = MOV32ri 42
348    RET 0, %eax
349
350  bb.4.ret_100:
351    %eax = MOV32ri 100
352    RET 0, %eax
353
354...
355---
356name:            no_hoist_across_call
357# CHECK-LABEL: name:            no_hoist_across_call
358alignment:       4
359tracksRegLiveness: true
360liveins:
361  - { reg: '%rdi' }
362calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx',
363                        '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15',
364                        '%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d',
365                        '%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ]
366# CHECK: body:
367# CHECK-NOT: FAULTING_LOAD_OP
368# CHECK: bb.1.stay:
369# CHECK: CALL64pcrel32
370body:             |
371  bb.0.entry:
372    successors: %bb.2.leave, %bb.1.stay
373    liveins: %rdi, %rbx
374
375    frame-setup PUSH64r killed %rbx, implicit-def %rsp, implicit %rsp
376    CFI_INSTRUCTION def_cfa_offset 16
377    CFI_INSTRUCTION offset %rbx, -16
378    %rbx = MOV64rr %rdi
379    TEST64rr %rbx, %rbx, implicit-def %eflags
380    JE_1 %bb.2.leave, implicit killed %eflags
381
382  bb.1.stay:
383    liveins: %rbx
384
385    CALL64pcrel32 @f, csr_64, implicit %rsp, implicit-def %rsp
386    %eax = MOV32rm killed %rbx, 1, _, 0, _ :: (load 4 from %ir.ptr)
387    %rbx = POP64r implicit-def %rsp, implicit %rsp
388    RETQ %eax
389
390  bb.2.leave:
391    %eax = XOR32rr undef %eax, undef %eax, implicit-def dead %eflags
392    %rbx = POP64r implicit-def %rsp, implicit %rsp
393    RETQ %eax
394
395...
396---
397name:            dependency_live_in_hazard
398# CHECK-LABEL: name:            dependency_live_in_hazard
399# CHECK:   bb.0.entry:
400# CHECK-NOT: FAULTING_LOAD_OP
401# CHECK: bb.1.not_null:
402
403# Make sure that the BEXTR32rm instruction below is not used to emit
404# an implicit null check -- hoisting it will require hosting the move
405# to %esi and we cannot do that without clobbering the use of %rsi in
406# the first instruction in bb.1.not_null.
407alignment:       4
408tracksRegLiveness: true
409liveins:
410  - { reg: '%rdi' }
411  - { reg: '%rsi' }
412body:             |
413  bb.0.entry:
414    successors: %bb.2.is_null, %bb.1.not_null
415    liveins: %rdi, %rsi
416
417    TEST64rr %rdi, %rdi, implicit-def %eflags
418    JE_1 %bb.2.is_null, implicit killed %eflags
419
420  bb.1.not_null:
421    liveins: %rdi, %rsi
422
423    %rcx = MOV64rm killed %rsi, 1, _, 0, _ :: (load 8 from %ir.ptr2)
424    %esi = MOV32ri 3076
425    %eax = BEXTR32rm killed %rdi, 1, _, 0, _, killed %esi, implicit-def dead %eflags :: (load 4 from %ir.ptr)
426    %eax = ADD32rm killed %eax, killed %rcx, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.val)
427    RETQ %eax
428
429  bb.2.is_null:
430    %eax = XOR32rr undef %eax, undef %eax, implicit-def dead %eflags
431    RETQ %eax
432
433...
434