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  declare void @f() readonly
83
84  define i32 @no_hoist_across_call(i32* %ptr) {
85  entry:
86    %is_null = icmp eq i32* %ptr, null
87    br i1 %is_null, label %leave, label %stay, !make.implicit !0
88
89  stay:
90    call void @f()
91    %val = load i32, i32* %ptr
92    ret i32 %val
93
94  leave:
95    ret i32 0
96  }
97
98  define i32 @dependency_live_in_hazard(i32* %ptr, i32** %ptr2, i32* %ptr3) #0 {
99  entry:
100    %val = load i32*, i32** %ptr2
101    %ptr_is_null = icmp eq i32* %ptr, null
102    br i1 %ptr_is_null, label %is_null, label %not_null, !make.implicit !0
103
104  not_null:                                         ; preds = %entry
105    %addend = load i32, i32* %val
106    %result = load i32, i32* %ptr
107    %result.shr = lshr i32 %result, 4
108    %result.and = and i32 %result.shr, 4095
109    %result.add = add i32 %addend, %result.and
110    ret i32 %result.add
111
112  is_null:                                          ; preds = %entry
113    ret i32 0
114  }
115
116  attributes #0 = { "target-features"="+bmi,+bmi2" }
117
118  !0 = !{}
119...
120---
121name:            imp_null_check_with_bitwise_op_0
122# CHECK-LABEL: name:            imp_null_check_with_bitwise_op_0
123alignment:       4
124tracksRegLiveness: true
125liveins:
126  - { reg: '%rdi' }
127  - { reg: '%esi' }
128# CHECK:  bb.0.entry:
129# CHECK:    %eax = MOV32ri 2200000
130# 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)
131# CHECK-NEXT:    JMP_1 %bb.1.not_null
132
133body:             |
134  bb.0.entry:
135    successors: %bb.3.is_null, %bb.1.not_null
136    liveins: %esi, %rdi
137
138    TEST64rr %rdi, %rdi, implicit-def %eflags
139    JE_1 %bb.3.is_null, implicit %eflags
140
141  bb.1.not_null:
142    successors: %bb.4.ret_100, %bb.2.ret_200
143    liveins: %esi, %rdi
144
145    %eax = MOV32ri 2200000
146    %eax = AND32rm killed %eax, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
147    CMP32rr killed %eax, killed %esi, implicit-def %eflags
148    JE_1 %bb.4.ret_100, implicit %eflags
149
150  bb.2.ret_200:
151    %eax = MOV32ri 200
152    RET 0, %eax
153
154  bb.3.is_null:
155    %eax = MOV32ri 42
156    RET 0, %eax
157
158  bb.4.ret_100:
159    %eax = MOV32ri 100
160    RET 0, %eax
161
162...
163---
164name:            imp_null_check_with_bitwise_op_1
165alignment:       4
166tracksRegLiveness: true
167liveins:
168  - { reg: '%rdi' }
169  - { reg: '%esi' }
170  - { reg: '%rdx' }
171# CHECK: bb.0.entry:
172# CHECK:    %eax = MOV32rm killed %rdx, 1, _, 0, _ :: (volatile load 4 from %ir.ptr)
173# CHECK-NEXT:    TEST64rr %rdi, %rdi, implicit-def %eflags
174# CHECK-NEXT:    JE_1 %bb.3.is_null, implicit %eflags
175
176body:             |
177  bb.0.entry:
178    successors: %bb.3.is_null, %bb.1.not_null
179    liveins: %esi, %rdi, %rdx
180
181    %eax = MOV32rm killed %rdx, 1, _, 0, _ :: (volatile load 4 from %ir.ptr)
182    TEST64rr %rdi, %rdi, implicit-def %eflags
183    JE_1 %bb.3.is_null, implicit %eflags
184
185  bb.1.not_null:
186    successors: %bb.4.ret_100, %bb.2.ret_200
187    liveins: %esi, %rdi
188
189    %eax = MOV32ri 2200000
190    %eax = AND32rm killed %eax, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
191    CMP32rr killed %eax, killed %esi, implicit-def %eflags
192    JE_1 %bb.4.ret_100, implicit %eflags
193
194  bb.2.ret_200:
195    successors: %bb.3.is_null
196
197    %eax = MOV32ri 200
198
199  bb.3.is_null:
200    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
201
202    RET 0, %eax
203
204  bb.4.ret_100:
205    %eax = MOV32ri 100
206    RET 0, %eax
207
208...
209---
210name:            imp_null_check_with_bitwise_op_2
211# CHECK-LABEL: name:            imp_null_check_with_bitwise_op_2
212alignment:       4
213tracksRegLiveness: true
214liveins:
215  - { reg: '%rdi' }
216  - { reg: '%esi' }
217# CHECK:  bb.0.entry:
218# CHECK:    TEST64rr %rdi, %rdi, implicit-def %eflags
219# CHECK-NEXT:    JE_1 %bb.3.is_null, implicit %eflags
220
221body:             |
222  bb.0.entry:
223    successors: %bb.3.is_null, %bb.1.not_null
224    liveins: %esi, %rdi
225
226    TEST64rr %rdi, %rdi, implicit-def %eflags
227    JE_1 %bb.3.is_null, implicit %eflags
228
229  bb.1.not_null:
230    successors: %bb.4.ret_100, %bb.2.ret_200
231    liveins: %esi, %rdi
232
233    %eax = MOV32ri 2200000
234    %eax = ADD32ri killed %eax, 100, implicit-def dead %eflags
235    %eax = AND32rm killed %eax, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
236    CMP32rr killed %eax, killed %esi, implicit-def %eflags
237    JE_1 %bb.4.ret_100, implicit %eflags
238
239  bb.2.ret_200:
240    %eax = MOV32ri 200
241    RET 0, %eax
242
243  bb.3.is_null:
244    %eax = MOV32ri 42
245    RET 0, %eax
246
247  bb.4.ret_100:
248    %eax = MOV32ri 100
249    RET 0, %eax
250
251...
252---
253name:            imp_null_check_with_bitwise_op_3
254# CHECK-LABEL: name:            imp_null_check_with_bitwise_op_3
255alignment:       4
256tracksRegLiveness: true
257liveins:
258  - { reg: '%rdi' }
259  - { reg: '%rsi' }
260# CHECK:  bb.0.entry:
261# CHECK:    TEST64rr %rdi, %rdi, implicit-def %eflags
262# CHECK-NEXT:    JE_1 %bb.3.is_null, implicit %eflags
263
264body:             |
265  bb.0.entry:
266    successors: %bb.3.is_null, %bb.1.not_null
267    liveins: %rsi, %rdi
268
269    TEST64rr %rdi, %rdi, implicit-def %eflags
270    JE_1 %bb.3.is_null, implicit %eflags
271
272  bb.1.not_null:
273    successors: %bb.4.ret_100, %bb.2.ret_200
274    liveins: %rsi, %rdi
275
276    %rdi  = MOV64ri 5000
277    %rdi = AND64rm killed %rdi, killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.x)
278    CMP64rr killed %rdi, killed %rsi, implicit-def %eflags
279    JE_1 %bb.4.ret_100, implicit %eflags
280
281  bb.2.ret_200:
282    %eax = MOV32ri 200
283    RET 0, %eax
284
285  bb.3.is_null:
286    %eax = MOV32ri 42
287    RET 0, %eax
288
289  bb.4.ret_100:
290    %eax = MOV32ri 100
291    RET 0, %eax
292
293...
294---
295name:            no_hoist_across_call
296# CHECK-LABEL: name:            no_hoist_across_call
297alignment:       4
298tracksRegLiveness: true
299liveins:
300  - { reg: '%rdi' }
301calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx',
302                        '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15',
303                        '%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d',
304                        '%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ]
305# CHECK: body:
306# CHECK-NOT: FAULTING_LOAD_OP
307# CHECK: bb.1.stay:
308# CHECK: CALL64pcrel32
309body:             |
310  bb.0.entry:
311    successors: %bb.2.leave, %bb.1.stay
312    liveins: %rdi, %rbx
313
314    frame-setup PUSH64r killed %rbx, implicit-def %rsp, implicit %rsp
315    CFI_INSTRUCTION def_cfa_offset 16
316    CFI_INSTRUCTION offset %rbx, -16
317    %rbx = MOV64rr %rdi
318    TEST64rr %rbx, %rbx, implicit-def %eflags
319    JE_1 %bb.2.leave, implicit killed %eflags
320
321  bb.1.stay:
322    liveins: %rbx
323
324    CALL64pcrel32 @f, csr_64, implicit %rsp, implicit-def %rsp
325    %eax = MOV32rm killed %rbx, 1, _, 0, _ :: (load 4 from %ir.ptr)
326    %rbx = POP64r implicit-def %rsp, implicit %rsp
327    RETQ %eax
328
329  bb.2.leave:
330    %eax = XOR32rr undef %eax, undef %eax, implicit-def dead %eflags
331    %rbx = POP64r implicit-def %rsp, implicit %rsp
332    RETQ %eax
333
334...
335---
336name:            dependency_live_in_hazard
337# CHECK-LABEL: name:            dependency_live_in_hazard
338# CHECK:   bb.0.entry:
339# CHECK-NOT: FAULTING_LOAD_OP
340# CHECK: bb.1.not_null:
341
342# Make sure that the BEXTR32rm instruction below is not used to emit
343# an implicit null check -- hoisting it will require hosting the move
344# to %esi and we cannot do that without clobbering the use of %rsi in
345# the first instruction in bb.1.not_null.
346alignment:       4
347tracksRegLiveness: true
348liveins:
349  - { reg: '%rdi' }
350  - { reg: '%rsi' }
351body:             |
352  bb.0.entry:
353    successors: %bb.2.is_null, %bb.1.not_null
354    liveins: %rdi, %rsi
355
356    TEST64rr %rdi, %rdi, implicit-def %eflags
357    JE_1 %bb.2.is_null, implicit killed %eflags
358
359  bb.1.not_null:
360    liveins: %rdi, %rsi
361
362    %rcx = MOV64rm killed %rsi, 1, _, 0, _ :: (load 8 from %ir.ptr2)
363    %esi = MOV32ri 3076
364    %eax = BEXTR32rm killed %rdi, 1, _, 0, _, killed %esi, implicit-def dead %eflags :: (load 4 from %ir.ptr)
365    %eax = ADD32rm killed %eax, killed %rcx, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.val)
366    RETQ %eax
367
368  bb.2.is_null:
369    %eax = XOR32rr undef %eax, undef %eax, implicit-def dead %eflags
370    RETQ %eax
371
372...
373