1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -verify-machineinstrs -O3 -mtriple=x86_64-apple-macosx -enable-implicit-null-checks < %s | FileCheck %s
3
4define i32 @imp_null_check_load(i32* %x) {
5; CHECK-LABEL: imp_null_check_load:
6; CHECK:       ## %bb.0: ## %entry
7; CHECK-NEXT:  Ltmp0:
8; CHECK-NEXT:    movl (%rdi), %eax ## on-fault: LBB0_1
9; CHECK-NEXT:  ## %bb.2: ## %not_null
10; CHECK-NEXT:    retq
11; CHECK-NEXT:  LBB0_1: ## %is_null
12; CHECK-NEXT:    movl $42, %eax
13; CHECK-NEXT:    retq
14
15 entry:
16  %c = icmp eq i32* %x, null
17  br i1 %c, label %is_null, label %not_null, !make.implicit !0
18
19 is_null:
20  ret i32 42
21
22 not_null:
23  %t = load i32, i32* %x
24  ret i32 %t
25}
26
27; TODO: can make implicit
28define i32 @imp_null_check_unordered_load(i32* %x) {
29; CHECK-LABEL: imp_null_check_unordered_load:
30; CHECK:       ## %bb.0: ## %entry
31; CHECK-NEXT:  Ltmp1:
32; CHECK-NEXT:    movl (%rdi), %eax ## on-fault: LBB1_1
33; CHECK-NEXT:  ## %bb.2: ## %not_null
34; CHECK-NEXT:    retq
35; CHECK-NEXT:  LBB1_1: ## %is_null
36; CHECK-NEXT:    movl $42, %eax
37; CHECK-NEXT:    retq
38
39 entry:
40  %c = icmp eq i32* %x, null
41  br i1 %c, label %is_null, label %not_null, !make.implicit !0
42
43 is_null:
44  ret i32 42
45
46 not_null:
47  %t = load atomic i32, i32* %x unordered, align 4
48  ret i32 %t
49}
50
51
52; TODO: Can be converted into implicit check.
53;; Probably could be implicit, but we're conservative for now
54define i32 @imp_null_check_seq_cst_load(i32* %x) {
55; CHECK-LABEL: imp_null_check_seq_cst_load:
56; CHECK:       ## %bb.0: ## %entry
57; CHECK-NEXT:    testq %rdi, %rdi
58; CHECK-NEXT:    je LBB2_1
59; CHECK-NEXT:  ## %bb.2: ## %not_null
60; CHECK-NEXT:    movl (%rdi), %eax
61; CHECK-NEXT:    retq
62; CHECK-NEXT:  LBB2_1: ## %is_null
63; CHECK-NEXT:    movl $42, %eax
64; CHECK-NEXT:    retq
65
66 entry:
67  %c = icmp eq i32* %x, null
68  br i1 %c, label %is_null, label %not_null, !make.implicit !0
69
70 is_null:
71  ret i32 42
72
73 not_null:
74  %t = load atomic i32, i32* %x seq_cst, align 4
75  ret i32 %t
76}
77
78;; Might be memory mapped IO, so can't rely on fault behavior
79define i32 @imp_null_check_volatile_load(i32* %x) {
80; CHECK-LABEL: imp_null_check_volatile_load:
81; CHECK:       ## %bb.0: ## %entry
82; CHECK-NEXT:    testq %rdi, %rdi
83; CHECK-NEXT:    je LBB3_1
84; CHECK-NEXT:  ## %bb.2: ## %not_null
85; CHECK-NEXT:    movl (%rdi), %eax
86; CHECK-NEXT:    retq
87; CHECK-NEXT:  LBB3_1: ## %is_null
88; CHECK-NEXT:    movl $42, %eax
89; CHECK-NEXT:    retq
90
91 entry:
92  %c = icmp eq i32* %x, null
93  br i1 %c, label %is_null, label %not_null, !make.implicit !0
94
95 is_null:
96  ret i32 42
97
98 not_null:
99  %t = load volatile i32, i32* %x, align 4
100  ret i32 %t
101}
102
103
104define i8 @imp_null_check_load_i8(i8* %x) {
105; CHECK-LABEL: imp_null_check_load_i8:
106; CHECK:       ## %bb.0: ## %entry
107; CHECK-NEXT:  Ltmp2:
108; CHECK-NEXT:    movb (%rdi), %al ## on-fault: LBB4_1
109; CHECK-NEXT:  ## %bb.2: ## %not_null
110; CHECK-NEXT:    retq
111; CHECK-NEXT:  LBB4_1: ## %is_null
112; CHECK-NEXT:    movb $42, %al
113; CHECK-NEXT:    retq
114
115 entry:
116  %c = icmp eq i8* %x, null
117  br i1 %c, label %is_null, label %not_null, !make.implicit !0
118
119 is_null:
120  ret i8 42
121
122 not_null:
123  %t = load i8, i8* %x
124  ret i8 %t
125}
126
127define i256 @imp_null_check_load_i256(i256* %x) {
128; CHECK-LABEL: imp_null_check_load_i256:
129; CHECK:       ## %bb.0: ## %entry
130; CHECK-NEXT:    movq %rdi, %rax
131; CHECK-NEXT:  Ltmp3:
132; CHECK-NEXT:    movq (%rsi), %rcx ## on-fault: LBB5_1
133; CHECK-NEXT:  ## %bb.2: ## %not_null
134; CHECK-NEXT:    movq 8(%rsi), %rdx
135; CHECK-NEXT:    movq 16(%rsi), %rdi
136; CHECK-NEXT:    movq 24(%rsi), %rsi
137; CHECK-NEXT:    movq %rsi, 24(%rax)
138; CHECK-NEXT:    movq %rdi, 16(%rax)
139; CHECK-NEXT:    movq %rdx, 8(%rax)
140; CHECK-NEXT:    movq %rcx, (%rax)
141; CHECK-NEXT:    retq
142; CHECK-NEXT:  LBB5_1: ## %is_null
143; CHECK-NEXT:    movq $0, 24(%rax)
144; CHECK-NEXT:    movq $0, 16(%rax)
145; CHECK-NEXT:    movq $0, 8(%rax)
146; CHECK-NEXT:    movq $42, (%rax)
147; CHECK-NEXT:    retq
148
149 entry:
150  %c = icmp eq i256* %x, null
151  br i1 %c, label %is_null, label %not_null, !make.implicit !0
152
153 is_null:
154  ret i256 42
155
156 not_null:
157  %t = load i256, i256* %x
158  ret i256 %t
159}
160
161
162
163define i32 @imp_null_check_gep_load(i32* %x) {
164; CHECK-LABEL: imp_null_check_gep_load:
165; CHECK:       ## %bb.0: ## %entry
166; CHECK-NEXT:  Ltmp4:
167; CHECK-NEXT:    movl 128(%rdi), %eax ## on-fault: LBB6_1
168; CHECK-NEXT:  ## %bb.2: ## %not_null
169; CHECK-NEXT:    retq
170; CHECK-NEXT:  LBB6_1: ## %is_null
171; CHECK-NEXT:    movl $42, %eax
172; CHECK-NEXT:    retq
173
174 entry:
175  %c = icmp eq i32* %x, null
176  br i1 %c, label %is_null, label %not_null, !make.implicit !0
177
178 is_null:
179  ret i32 42
180
181 not_null:
182  %x.gep = getelementptr i32, i32* %x, i32 32
183  %t = load i32, i32* %x.gep
184  ret i32 %t
185}
186
187define i32 @imp_null_check_add_result(i32* %x, i32 %p) {
188; CHECK-LABEL: imp_null_check_add_result:
189; CHECK:       ## %bb.0: ## %entry
190; CHECK-NEXT:  Ltmp5:
191; CHECK-NEXT:    addl (%rdi), %esi ## on-fault: LBB7_1
192; CHECK-NEXT:  ## %bb.2: ## %not_null
193; CHECK-NEXT:    movl %esi, %eax
194; CHECK-NEXT:    retq
195; CHECK-NEXT:  LBB7_1: ## %is_null
196; CHECK-NEXT:    movl $42, %eax
197; CHECK-NEXT:    retq
198
199 entry:
200  %c = icmp eq i32* %x, null
201  br i1 %c, label %is_null, label %not_null, !make.implicit !0
202
203 is_null:
204  ret i32 42
205
206 not_null:
207  %t = load i32, i32* %x
208  %p1 = add i32 %t, %p
209  ret i32 %p1
210}
211
212define i32 @imp_null_check_sub_result(i32* %x, i32 %p) {
213; CHECK-LABEL: imp_null_check_sub_result:
214; CHECK:       ## %bb.0: ## %entry
215; CHECK-NEXT:  Ltmp6:
216; CHECK-NEXT:    movl (%rdi), %eax ## on-fault: LBB8_1
217; CHECK-NEXT:  ## %bb.2: ## %not_null
218; CHECK-NEXT:    subl %esi, %eax
219; CHECK-NEXT:    retq
220; CHECK-NEXT:  LBB8_1: ## %is_null
221; CHECK-NEXT:    movl $42, %eax
222; CHECK-NEXT:    retq
223
224 entry:
225  %c = icmp eq i32* %x, null
226  br i1 %c, label %is_null, label %not_null, !make.implicit !0
227
228 is_null:
229  ret i32 42
230
231 not_null:
232  %t = load i32, i32* %x
233  %p1 = sub i32 %t, %p
234  ret i32 %p1
235}
236
237define i32 @imp_null_check_mul_result(i32* %x, i32 %p) {
238; CHECK-LABEL: imp_null_check_mul_result:
239; CHECK:       ## %bb.0: ## %entry
240; CHECK-NEXT:  Ltmp7:
241; CHECK-NEXT:    imull (%rdi), %esi ## on-fault: LBB9_1
242; CHECK-NEXT:  ## %bb.2: ## %not_null
243; CHECK-NEXT:    movl %esi, %eax
244; CHECK-NEXT:    retq
245; CHECK-NEXT:  LBB9_1: ## %is_null
246; CHECK-NEXT:    movl $42, %eax
247; CHECK-NEXT:    retq
248
249 entry:
250  %c = icmp eq i32* %x, null
251  br i1 %c, label %is_null, label %not_null, !make.implicit !0
252
253 is_null:
254  ret i32 42
255
256 not_null:
257  %t = load i32, i32* %x
258  %p1 = mul i32 %t, %p
259  ret i32 %p1
260}
261
262define i32 @imp_null_check_udiv_result(i32* %x, i32 %p) {
263; CHECK-LABEL: imp_null_check_udiv_result:
264; CHECK:       ## %bb.0: ## %entry
265; CHECK-NEXT:  Ltmp8:
266; CHECK-NEXT:    movl (%rdi), %eax ## on-fault: LBB10_1
267; CHECK-NEXT:  ## %bb.2: ## %not_null
268; CHECK-NEXT:    xorl %edx, %edx
269; CHECK-NEXT:    divl %esi
270; CHECK-NEXT:    retq
271; CHECK-NEXT:  LBB10_1: ## %is_null
272; CHECK-NEXT:    movl $42, %eax
273; CHECK-NEXT:    retq
274
275 entry:
276  %c = icmp eq i32* %x, null
277  br i1 %c, label %is_null, label %not_null, !make.implicit !0
278
279 is_null:
280  ret i32 42
281
282 not_null:
283  %t = load i32, i32* %x
284  %p1 = udiv i32 %t, %p
285  ret i32 %p1
286}
287
288define i32 @imp_null_check_shl_result(i32* %x, i32 %p) {
289; CHECK-LABEL: imp_null_check_shl_result:
290; CHECK:       ## %bb.0: ## %entry
291; CHECK-NEXT:  Ltmp9:
292; CHECK-NEXT:    movl (%rdi), %eax ## on-fault: LBB11_1
293; CHECK-NEXT:  ## %bb.2: ## %not_null
294; CHECK-NEXT:    movl %esi, %ecx
295; CHECK-NEXT:    shll %cl, %eax
296; CHECK-NEXT:    retq
297; CHECK-NEXT:  LBB11_1: ## %is_null
298; CHECK-NEXT:    movl $42, %eax
299; CHECK-NEXT:    retq
300
301 entry:
302  %c = icmp eq i32* %x, null
303  br i1 %c, label %is_null, label %not_null, !make.implicit !0
304
305 is_null:
306  ret i32 42
307
308 not_null:
309  %t = load i32, i32* %x
310  %p1 = shl i32 %t, %p
311  ret i32 %p1
312}
313
314define i32 @imp_null_check_lshr_result(i32* %x, i32 %p) {
315; CHECK-LABEL: imp_null_check_lshr_result:
316; CHECK:       ## %bb.0: ## %entry
317; CHECK-NEXT:  Ltmp10:
318; CHECK-NEXT:    movl (%rdi), %eax ## on-fault: LBB12_1
319; CHECK-NEXT:  ## %bb.2: ## %not_null
320; CHECK-NEXT:    movl %esi, %ecx
321; CHECK-NEXT:    shrl %cl, %eax
322; CHECK-NEXT:    retq
323; CHECK-NEXT:  LBB12_1: ## %is_null
324; CHECK-NEXT:    movl $42, %eax
325; CHECK-NEXT:    retq
326
327 entry:
328  %c = icmp eq i32* %x, null
329  br i1 %c, label %is_null, label %not_null, !make.implicit !0
330
331 is_null:
332  ret i32 42
333
334 not_null:
335  %t = load i32, i32* %x
336  %p1 = lshr i32 %t, %p
337  ret i32 %p1
338}
339
340
341
342
343define i32 @imp_null_check_hoist_over_unrelated_load(i32* %x, i32* %y, i32* %z) {
344; CHECK-LABEL: imp_null_check_hoist_over_unrelated_load:
345; CHECK:       ## %bb.0: ## %entry
346; CHECK-NEXT:  Ltmp11:
347; CHECK-NEXT:    movl (%rdi), %eax ## on-fault: LBB13_1
348; CHECK-NEXT:  ## %bb.2: ## %not_null
349; CHECK-NEXT:    movl (%rsi), %ecx
350; CHECK-NEXT:    movl %ecx, (%rdx)
351; CHECK-NEXT:    retq
352; CHECK-NEXT:  LBB13_1: ## %is_null
353; CHECK-NEXT:    movl $42, %eax
354; CHECK-NEXT:    retq
355
356 entry:
357  %c = icmp eq i32* %x, null
358  br i1 %c, label %is_null, label %not_null, !make.implicit !0
359
360 is_null:
361  ret i32 42
362
363 not_null:
364  %t0 = load i32, i32* %y
365  %t1 = load i32, i32* %x
366  store i32 %t0, i32* %z
367  ret i32 %t1
368}
369
370define i32 @imp_null_check_via_mem_comparision(i32* %x, i32 %val) {
371; CHECK-LABEL: imp_null_check_via_mem_comparision:
372; CHECK:       ## %bb.0: ## %entry
373; CHECK-NEXT:  Ltmp12:
374; CHECK-NEXT:    cmpl %esi, 4(%rdi) ## on-fault: LBB14_3
375; CHECK-NEXT:  ## %bb.1: ## %not_null
376; CHECK-NEXT:    jge LBB14_2
377; CHECK-NEXT:  ## %bb.4: ## %ret_100
378; CHECK-NEXT:    movl $100, %eax
379; CHECK-NEXT:    retq
380; CHECK-NEXT:  LBB14_3: ## %is_null
381; CHECK-NEXT:    movl $42, %eax
382; CHECK-NEXT:    retq
383; CHECK-NEXT:  LBB14_2: ## %ret_200
384; CHECK-NEXT:    movl $200, %eax
385; CHECK-NEXT:    retq
386
387 entry:
388  %c = icmp eq i32* %x, null
389  br i1 %c, label %is_null, label %not_null, !make.implicit !0
390
391 is_null:
392  ret i32 42
393
394 not_null:
395  %x.loc = getelementptr i32, i32* %x, i32 1
396  %t = load i32, i32* %x.loc
397  %m = icmp slt i32 %t, %val
398  br i1 %m, label %ret_100, label %ret_200
399
400 ret_100:
401  ret i32 100
402
403 ret_200:
404  ret i32 200
405}
406
407define i32 @imp_null_check_gep_load_with_use_dep(i32* %x, i32 %a) {
408; CHECK-LABEL: imp_null_check_gep_load_with_use_dep:
409; CHECK:       ## %bb.0: ## %entry
410; CHECK-NEXT:    ## kill: def $esi killed $esi def $rsi
411; CHECK-NEXT:  Ltmp13:
412; CHECK-NEXT:    movl (%rdi), %eax ## on-fault: LBB15_1
413; CHECK-NEXT:  ## %bb.2: ## %not_null
414; CHECK-NEXT:    addl %edi, %esi
415; CHECK-NEXT:    leal 4(%rax,%rsi), %eax
416; CHECK-NEXT:    retq
417; CHECK-NEXT:  LBB15_1: ## %is_null
418; CHECK-NEXT:    movl $42, %eax
419; CHECK-NEXT:    retq
420
421 entry:
422  %c = icmp eq i32* %x, null
423  br i1 %c, label %is_null, label %not_null, !make.implicit !0
424
425 is_null:
426  ret i32 42
427
428 not_null:
429  %x.loc = getelementptr i32, i32* %x, i32 1
430  %y = ptrtoint i32* %x.loc to i32
431  %b = add i32 %a, %y
432  %t = load i32, i32* %x
433  %z = add i32 %t, %b
434  ret i32 %z
435}
436
437;; TODO: We could handle this case as we can lift the fence into the
438;; previous block before the conditional without changing behavior.
439define i32 @imp_null_check_load_fence1(i32* %x) {
440; CHECK-LABEL: imp_null_check_load_fence1:
441; CHECK:       ## %bb.0: ## %entry
442; CHECK-NEXT:    testq %rdi, %rdi
443; CHECK-NEXT:    je LBB16_1
444; CHECK-NEXT:  ## %bb.2: ## %not_null
445; CHECK-NEXT:    ##MEMBARRIER
446; CHECK-NEXT:    movl (%rdi), %eax
447; CHECK-NEXT:    retq
448; CHECK-NEXT:  LBB16_1: ## %is_null
449; CHECK-NEXT:    movl $42, %eax
450; CHECK-NEXT:    retq
451
452entry:
453  %c = icmp eq i32* %x, null
454  br i1 %c, label %is_null, label %not_null, !make.implicit !0
455
456is_null:
457  ret i32 42
458
459not_null:
460  fence acquire
461  %t = load i32, i32* %x
462  ret i32 %t
463}
464
465;; TODO: We could handle this case as we can lift the fence into the
466;; previous block before the conditional without changing behavior.
467define i32 @imp_null_check_load_fence2(i32* %x) {
468; CHECK-LABEL: imp_null_check_load_fence2:
469; CHECK:       ## %bb.0: ## %entry
470; CHECK-NEXT:    testq %rdi, %rdi
471; CHECK-NEXT:    je LBB17_1
472; CHECK-NEXT:  ## %bb.2: ## %not_null
473; CHECK-NEXT:    mfence
474; CHECK-NEXT:    movl (%rdi), %eax
475; CHECK-NEXT:    retq
476; CHECK-NEXT:  LBB17_1: ## %is_null
477; CHECK-NEXT:    movl $42, %eax
478; CHECK-NEXT:    retq
479
480entry:
481  %c = icmp eq i32* %x, null
482  br i1 %c, label %is_null, label %not_null, !make.implicit !0
483
484is_null:
485  ret i32 42
486
487not_null:
488  fence seq_cst
489  %t = load i32, i32* %x
490  ret i32 %t
491}
492
493define void @imp_null_check_store(i32* %x) {
494; CHECK-LABEL: imp_null_check_store:
495; CHECK:       ## %bb.0: ## %entry
496; CHECK-NEXT:  Ltmp14:
497; CHECK-NEXT:    movl $1, (%rdi) ## on-fault: LBB18_1
498; CHECK-NEXT:  ## %bb.2: ## %not_null
499; CHECK-NEXT:    retq
500; CHECK-NEXT:  LBB18_1: ## %is_null
501; CHECK-NEXT:    retq
502
503 entry:
504  %c = icmp eq i32* %x, null
505  br i1 %c, label %is_null, label %not_null, !make.implicit !0
506
507 is_null:
508  ret void
509
510 not_null:
511  store i32 1, i32* %x
512  ret void
513}
514
515;; TODO: can be implicit
516define void @imp_null_check_unordered_store(i32* %x) {
517; CHECK-LABEL: imp_null_check_unordered_store:
518; CHECK:       ## %bb.0: ## %entry
519; CHECK-NEXT:  Ltmp15:
520; CHECK-NEXT:    movl $1, (%rdi) ## on-fault: LBB19_1
521; CHECK-NEXT:  ## %bb.2: ## %not_null
522; CHECK-NEXT:    retq
523; CHECK-NEXT:  LBB19_1: ## %is_null
524; CHECK-NEXT:    retq
525
526 entry:
527  %c = icmp eq i32* %x, null
528  br i1 %c, label %is_null, label %not_null, !make.implicit !0
529
530 is_null:
531  ret void
532
533 not_null:
534  store atomic i32 1, i32* %x unordered, align 4
535  ret void
536}
537
538define i32 @imp_null_check_neg_gep_load(i32* %x) {
539; CHECK-LABEL: imp_null_check_neg_gep_load:
540; CHECK:       ## %bb.0: ## %entry
541; CHECK-NEXT:  Ltmp16:
542; CHECK-NEXT:    movl -128(%rdi), %eax ## on-fault: LBB20_1
543; CHECK-NEXT:  ## %bb.2: ## %not_null
544; CHECK-NEXT:    retq
545; CHECK-NEXT:  LBB20_1: ## %is_null
546; CHECK-NEXT:    movl $42, %eax
547; CHECK-NEXT:    retq
548
549 entry:
550  %c = icmp eq i32* %x, null
551  br i1 %c, label %is_null, label %not_null, !make.implicit !0
552
553 is_null:
554  ret i32 42
555
556 not_null:
557  %x.gep = getelementptr i32, i32* %x, i32 -32
558  %t = load i32, i32* %x.gep
559  ret i32 %t
560}
561
562; This redefines the null check reg by doing a zero-extend and a shift on
563; itself.
564; Converted into implicit null check since both of these operations do not
565; change the nullness of %x (i.e. if it is null, it remains null).
566define i64 @imp_null_check_load_shift_addr(i64* %x) {
567; CHECK-LABEL: imp_null_check_load_shift_addr:
568; CHECK:       ## %bb.0: ## %entry
569; CHECK-NEXT:    shlq $6, %rdi
570; CHECK-NEXT:  Ltmp17:
571; CHECK-NEXT:    movq 8(%rdi), %rax ## on-fault: LBB21_1
572; CHECK-NEXT:  ## %bb.2: ## %not_null
573; CHECK-NEXT:    retq
574; CHECK-NEXT:  LBB21_1: ## %is_null
575; CHECK-NEXT:    movl $42, %eax
576; CHECK-NEXT:    retq
577
578  entry:
579   %c = icmp eq i64* %x, null
580   br i1 %c, label %is_null, label %not_null, !make.implicit !0
581
582  is_null:
583   ret i64 42
584
585  not_null:
586   %y = ptrtoint i64* %x to i64
587   %shry = shl i64 %y, 6
588   %y.ptr = inttoptr i64 %shry to i64*
589   %x.loc = getelementptr i64, i64* %y.ptr, i64 1
590   %t = load i64, i64* %x.loc
591   ret i64 %t
592}
593
594; Same as imp_null_check_load_shift_addr but shift is by 3 and this is now
595; converted into complex addressing.
596; TODO: Can be converted into implicit null check
597define i64 @imp_null_check_load_shift_by_3_addr(i64* %x) {
598; CHECK-LABEL: imp_null_check_load_shift_by_3_addr:
599; CHECK:       ## %bb.0: ## %entry
600; CHECK-NEXT:    testq %rdi, %rdi
601; CHECK-NEXT:    je LBB22_1
602; CHECK-NEXT:  ## %bb.2: ## %not_null
603; CHECK-NEXT:    movq 8(,%rdi,8), %rax
604; CHECK-NEXT:    retq
605; CHECK-NEXT:  LBB22_1: ## %is_null
606; CHECK-NEXT:    movl $42, %eax
607; CHECK-NEXT:    retq
608
609  entry:
610   %c = icmp eq i64* %x, null
611   br i1 %c, label %is_null, label %not_null, !make.implicit !0
612
613  is_null:
614   ret i64 42
615
616  not_null:
617   %y = ptrtoint i64* %x to i64
618   %shry = shl i64 %y, 3
619   %y.ptr = inttoptr i64 %shry to i64*
620   %x.loc = getelementptr i64, i64* %y.ptr, i64 1
621   %t = load i64, i64* %x.loc
622   ret i64 %t
623}
624!0 = !{}
625