1 ; RUN: llc -verify-machineinstrs -O3 -mtriple=x86_64-apple-macosx -enable-implicit-null-checks < %s | FileCheck %s
3 define i32 @imp_null_check_load(ptr %x) {
4 ; CHECK-LABEL: imp_null_check_load:
5 ; CHECK: ## %bb.0: ## %entry
7 ; CHECK-NEXT: movl (%rdi), %eax ## on-fault: LBB0_1
8 ; CHECK-NEXT: ## %bb.2: ## %not_null
10 ; CHECK-NEXT: LBB0_1: ## %is_null
11 ; CHECK-NEXT: movl $42, %eax
15 %c = icmp eq ptr %x, null
16 br i1 %c, label %is_null, label %not_null, !make.implicit !0
26 ; TODO: can make implicit
27 define i32 @imp_null_check_unordered_load(ptr %x) {
28 ; CHECK-LABEL: imp_null_check_unordered_load:
29 ; CHECK: ## %bb.0: ## %entry
31 ; CHECK-NEXT: movl (%rdi), %eax ## on-fault: LBB1_1
32 ; CHECK-NEXT: ## %bb.2: ## %not_null
34 ; CHECK-NEXT: LBB1_1: ## %is_null
35 ; CHECK-NEXT: movl $42, %eax
39 %c = icmp eq ptr %x, null
40 br i1 %c, label %is_null, label %not_null, !make.implicit !0
46 %t = load atomic i32, ptr %x unordered, align 4
51 ; TODO: Can be converted into implicit check.
52 ;; Probably could be implicit, but we're conservative for now
53 define i32 @imp_null_check_seq_cst_load(ptr %x) {
54 ; CHECK-LABEL: imp_null_check_seq_cst_load:
55 ; CHECK: ## %bb.0: ## %entry
56 ; CHECK-NEXT: testq %rdi, %rdi
57 ; CHECK-NEXT: je LBB2_1
58 ; CHECK-NEXT: ## %bb.2: ## %not_null
59 ; CHECK-NEXT: movl (%rdi), %eax
61 ; CHECK-NEXT: LBB2_1: ## %is_null
62 ; CHECK-NEXT: movl $42, %eax
66 %c = icmp eq ptr %x, null
67 br i1 %c, label %is_null, label %not_null, !make.implicit !0
73 %t = load atomic i32, ptr %x seq_cst, align 4
77 ;; Might be memory mapped IO, so can't rely on fault behavior
78 define i32 @imp_null_check_volatile_load(ptr %x) {
79 ; CHECK-LABEL: imp_null_check_volatile_load:
80 ; CHECK: ## %bb.0: ## %entry
81 ; CHECK-NEXT: testq %rdi, %rdi
82 ; CHECK-NEXT: je LBB3_1
83 ; CHECK-NEXT: ## %bb.2: ## %not_null
84 ; CHECK-NEXT: movl (%rdi), %eax
86 ; CHECK-NEXT: LBB3_1: ## %is_null
87 ; CHECK-NEXT: movl $42, %eax
91 %c = icmp eq ptr %x, null
92 br i1 %c, label %is_null, label %not_null, !make.implicit !0
98 %t = load volatile i32, ptr %x, align 4
103 define i8 @imp_null_check_load_i8(ptr %x) {
104 ; CHECK-LABEL: imp_null_check_load_i8:
105 ; CHECK: ## %bb.0: ## %entry
107 ; CHECK-NEXT: movb (%rdi), %al ## on-fault: LBB4_1
108 ; CHECK-NEXT: ## %bb.2: ## %not_null
110 ; CHECK-NEXT: LBB4_1: ## %is_null
111 ; CHECK-NEXT: movb $42, %al
115 %c = icmp eq ptr %x, null
116 br i1 %c, label %is_null, label %not_null, !make.implicit !0
126 define i256 @imp_null_check_load_i256(ptr %x) {
127 ; CHECK-LABEL: imp_null_check_load_i256:
128 ; CHECK: ## %bb.0: ## %entry
129 ; CHECK-NEXT: movq %rdi, %rax
131 ; CHECK-NEXT: movq (%rsi), %rcx ## on-fault: LBB5_1
132 ; CHECK-NEXT: ## %bb.2: ## %not_null
133 ; CHECK-NEXT: movq 8(%rsi), %rdx
134 ; CHECK-NEXT: movq 16(%rsi), %rdi
135 ; CHECK-NEXT: movq 24(%rsi), %rsi
136 ; CHECK-NEXT: movq %rsi, 24(%rax)
137 ; CHECK-NEXT: movq %rdi, 16(%rax)
138 ; CHECK-NEXT: movq %rdx, 8(%rax)
139 ; CHECK-NEXT: movq %rcx, (%rax)
141 ; CHECK-NEXT: LBB5_1: ## %is_null
142 ; CHECK-NEXT: movq $0, 24(%rax)
143 ; CHECK-NEXT: movq $0, 16(%rax)
144 ; CHECK-NEXT: movq $0, 8(%rax)
145 ; CHECK-NEXT: movq $42, (%rax)
149 %c = icmp eq ptr %x, null
150 br i1 %c, label %is_null, label %not_null, !make.implicit !0
156 %t = load i256, ptr %x
162 define i32 @imp_null_check_gep_load(ptr %x) {
163 ; CHECK-LABEL: imp_null_check_gep_load:
164 ; CHECK: ## %bb.0: ## %entry
166 ; CHECK-NEXT: movl 128(%rdi), %eax ## on-fault: LBB6_1
167 ; CHECK-NEXT: ## %bb.2: ## %not_null
169 ; CHECK-NEXT: LBB6_1: ## %is_null
170 ; CHECK-NEXT: movl $42, %eax
174 %c = icmp eq ptr %x, null
175 br i1 %c, label %is_null, label %not_null, !make.implicit !0
181 %x.gep = getelementptr i32, ptr %x, i32 32
182 %t = load i32, ptr %x.gep
186 define i32 @imp_null_check_add_result(ptr %x, i32 %p) {
187 ; CHECK-LABEL: imp_null_check_add_result:
188 ; CHECK: ## %bb.0: ## %entry
190 ; CHECK-NEXT: addl (%rdi), %esi ## on-fault: LBB7_1
191 ; CHECK-NEXT: ## %bb.2: ## %not_null
192 ; CHECK-NEXT: movl %esi, %eax
194 ; CHECK-NEXT: LBB7_1: ## %is_null
195 ; CHECK-NEXT: movl $42, %eax
199 %c = icmp eq ptr %x, null
200 br i1 %c, label %is_null, label %not_null, !make.implicit !0
206 %t = load i32, ptr %x
211 define i32 @imp_null_check_sub_result(ptr %x, i32 %p) {
212 ; CHECK-LABEL: imp_null_check_sub_result:
213 ; CHECK: ## %bb.0: ## %entry
215 ; CHECK-NEXT: movl (%rdi), %eax ## on-fault: LBB8_1
216 ; CHECK-NEXT: ## %bb.2: ## %not_null
217 ; CHECK-NEXT: subl %esi, %eax
219 ; CHECK-NEXT: LBB8_1: ## %is_null
220 ; CHECK-NEXT: movl $42, %eax
224 %c = icmp eq ptr %x, null
225 br i1 %c, label %is_null, label %not_null, !make.implicit !0
231 %t = load i32, ptr %x
236 define i32 @imp_null_check_mul_result(ptr %x, i32 %p) {
237 ; CHECK-LABEL: imp_null_check_mul_result:
238 ; CHECK: ## %bb.0: ## %entry
240 ; CHECK-NEXT: imull (%rdi), %esi ## on-fault: LBB9_1
241 ; CHECK-NEXT: ## %bb.2: ## %not_null
242 ; CHECK-NEXT: movl %esi, %eax
244 ; CHECK-NEXT: LBB9_1: ## %is_null
245 ; CHECK-NEXT: movl $42, %eax
249 %c = icmp eq ptr %x, null
250 br i1 %c, label %is_null, label %not_null, !make.implicit !0
256 %t = load i32, ptr %x
261 define i32 @imp_null_check_udiv_result(ptr %x, i32 %p) {
262 ; CHECK-LABEL: imp_null_check_udiv_result:
263 ; CHECK: ## %bb.0: ## %entry
265 ; CHECK-NEXT: movl (%rdi), %eax ## on-fault: LBB10_1
266 ; CHECK-NEXT: ## %bb.2: ## %not_null
267 ; CHECK-NEXT: xorl %edx, %edx
268 ; CHECK-NEXT: divl %esi
270 ; CHECK-NEXT: LBB10_1: ## %is_null
271 ; CHECK-NEXT: movl $42, %eax
275 %c = icmp eq ptr %x, null
276 br i1 %c, label %is_null, label %not_null, !make.implicit !0
282 %t = load i32, ptr %x
283 %p1 = udiv i32 %t, %p
287 define i32 @imp_null_check_shl_result(ptr %x, i32 %p) {
288 ; CHECK-LABEL: imp_null_check_shl_result:
289 ; CHECK: ## %bb.0: ## %entry
291 ; CHECK-NEXT: movl (%rdi), %eax ## on-fault: LBB11_1
292 ; CHECK-NEXT: ## %bb.2: ## %not_null
293 ; CHECK-NEXT: movl %esi, %ecx
294 ; CHECK-NEXT: shll %cl, %eax
296 ; CHECK-NEXT: LBB11_1: ## %is_null
297 ; CHECK-NEXT: movl $42, %eax
301 %c = icmp eq ptr %x, null
302 br i1 %c, label %is_null, label %not_null, !make.implicit !0
308 %t = load i32, ptr %x
313 define i32 @imp_null_check_lshr_result(ptr %x, i32 %p) {
314 ; CHECK-LABEL: imp_null_check_lshr_result:
315 ; CHECK: ## %bb.0: ## %entry
316 ; CHECK-NEXT: Ltmp10:
317 ; CHECK-NEXT: movl (%rdi), %eax ## on-fault: LBB12_1
318 ; CHECK-NEXT: ## %bb.2: ## %not_null
319 ; CHECK-NEXT: movl %esi, %ecx
320 ; CHECK-NEXT: shrl %cl, %eax
322 ; CHECK-NEXT: LBB12_1: ## %is_null
323 ; CHECK-NEXT: movl $42, %eax
327 %c = icmp eq ptr %x, null
328 br i1 %c, label %is_null, label %not_null, !make.implicit !0
334 %t = load i32, ptr %x
335 %p1 = lshr i32 %t, %p
342 define i32 @imp_null_check_hoist_over_unrelated_load(ptr %x, ptr %y, ptr %z) {
343 ; CHECK-LABEL: imp_null_check_hoist_over_unrelated_load:
344 ; CHECK: ## %bb.0: ## %entry
345 ; CHECK-NEXT: Ltmp11:
346 ; CHECK-NEXT: movl (%rdi), %eax ## on-fault: LBB13_1
347 ; CHECK-NEXT: ## %bb.2: ## %not_null
348 ; CHECK-NEXT: movl (%rsi), %ecx
349 ; CHECK-NEXT: movl %ecx, (%rdx)
351 ; CHECK-NEXT: LBB13_1: ## %is_null
352 ; CHECK-NEXT: movl $42, %eax
356 %c = icmp eq ptr %x, null
357 br i1 %c, label %is_null, label %not_null, !make.implicit !0
363 %t0 = load i32, ptr %y
364 %t1 = load i32, ptr %x
365 store i32 %t0, ptr %z
369 define i32 @imp_null_check_via_mem_comparision(ptr %x, i32 %val) {
370 ; CHECK-LABEL: imp_null_check_via_mem_comparision:
371 ; CHECK: ## %bb.0: ## %entry
372 ; CHECK-NEXT: Ltmp12:
373 ; CHECK-NEXT: cmpl %esi, 4(%rdi) ## on-fault: LBB14_3
374 ; CHECK-NEXT: ## %bb.1: ## %not_null
375 ; CHECK-NEXT: jge LBB14_2
376 ; CHECK-NEXT: ## %bb.4: ## %ret_100
377 ; CHECK-NEXT: movl $100, %eax
379 ; CHECK-NEXT: LBB14_3: ## %is_null
380 ; CHECK-NEXT: movl $42, %eax
382 ; CHECK-NEXT: LBB14_2: ## %ret_200
383 ; CHECK-NEXT: movl $200, %eax
387 %c = icmp eq ptr %x, null
388 br i1 %c, label %is_null, label %not_null, !make.implicit !0
394 %x.loc = getelementptr i32, ptr %x, i32 1
395 %t = load i32, ptr %x.loc
396 %m = icmp slt i32 %t, %val
397 br i1 %m, label %ret_100, label %ret_200
406 define i32 @imp_null_check_gep_load_with_use_dep(ptr %x, i32 %a) {
407 ; CHECK-LABEL: imp_null_check_gep_load_with_use_dep:
408 ; CHECK: ## %bb.0: ## %entry
409 ; CHECK-NEXT: ## kill: def $esi killed $esi def $rsi
410 ; CHECK-NEXT: Ltmp13:
411 ; CHECK-NEXT: movl (%rdi), %eax ## on-fault: LBB15_1
412 ; CHECK-NEXT: ## %bb.2: ## %not_null
413 ; CHECK-NEXT: addl %edi, %esi
414 ; CHECK-NEXT: leal 4(%rax,%rsi), %eax
416 ; CHECK-NEXT: LBB15_1: ## %is_null
417 ; CHECK-NEXT: movl $42, %eax
421 %c = icmp eq ptr %x, null
422 br i1 %c, label %is_null, label %not_null, !make.implicit !0
428 %x.loc = getelementptr i32, ptr %x, i32 1
429 %y = ptrtoint ptr %x.loc to i32
431 %t = load i32, ptr %x
436 ;; TODO: We could handle this case as we can lift the fence into the
437 ;; previous block before the conditional without changing behavior.
438 define i32 @imp_null_check_load_fence1(ptr %x) {
439 ; CHECK-LABEL: imp_null_check_load_fence1:
440 ; CHECK: ## %bb.0: ## %entry
441 ; CHECK-NEXT: testq %rdi, %rdi
442 ; CHECK-NEXT: je LBB16_1
443 ; CHECK-NEXT: ## %bb.2: ## %not_null
444 ; CHECK-NEXT: ##MEMBARRIER
445 ; CHECK-NEXT: movl (%rdi), %eax
447 ; CHECK-NEXT: LBB16_1: ## %is_null
448 ; CHECK-NEXT: movl $42, %eax
452 %c = icmp eq ptr %x, null
453 br i1 %c, label %is_null, label %not_null, !make.implicit !0
460 %t = load i32, ptr %x
464 ;; TODO: We could handle this case as we can lift the fence into the
465 ;; previous block before the conditional without changing behavior.
466 define i32 @imp_null_check_load_fence2(ptr %x) {
467 ; CHECK-LABEL: imp_null_check_load_fence2:
468 ; CHECK: ## %bb.0: ## %entry
469 ; CHECK-NEXT: testq %rdi, %rdi
470 ; CHECK-NEXT: je LBB17_1
471 ; CHECK-NEXT: ## %bb.2: ## %not_null
473 ; CHECK-NEXT: movl (%rdi), %eax
475 ; CHECK-NEXT: LBB17_1: ## %is_null
476 ; CHECK-NEXT: movl $42, %eax
480 %c = icmp eq ptr %x, null
481 br i1 %c, label %is_null, label %not_null, !make.implicit !0
488 %t = load i32, ptr %x
492 define void @imp_null_check_store(ptr %x) {
493 ; CHECK-LABEL: imp_null_check_store:
494 ; CHECK: ## %bb.0: ## %entry
495 ; CHECK-NEXT: Ltmp14:
496 ; CHECK-NEXT: movl $1, (%rdi) ## on-fault: LBB18_1
497 ; CHECK-NEXT: ## %bb.2: ## %not_null
499 ; CHECK-NEXT: LBB18_1: ## %is_null
503 %c = icmp eq ptr %x, null
504 br i1 %c, label %is_null, label %not_null, !make.implicit !0
514 ;; TODO: can be implicit
515 define void @imp_null_check_unordered_store(ptr %x) {
516 ; CHECK-LABEL: imp_null_check_unordered_store:
517 ; CHECK: ## %bb.0: ## %entry
518 ; CHECK-NEXT: Ltmp15:
519 ; CHECK-NEXT: movl $1, (%rdi) ## on-fault: LBB19_1
520 ; CHECK-NEXT: ## %bb.2: ## %not_null
522 ; CHECK-NEXT: LBB19_1: ## %is_null
526 %c = icmp eq ptr %x, null
527 br i1 %c, label %is_null, label %not_null, !make.implicit !0
533 store atomic i32 1, ptr %x unordered, align 4
537 define i32 @imp_null_check_neg_gep_load(ptr %x) {
538 ; CHECK-LABEL: imp_null_check_neg_gep_load:
539 ; CHECK: ## %bb.0: ## %entry
540 ; CHECK-NEXT: Ltmp16:
541 ; CHECK-NEXT: movl -128(%rdi), %eax ## on-fault: LBB20_1
542 ; CHECK-NEXT: ## %bb.2: ## %not_null
544 ; CHECK-NEXT: LBB20_1: ## %is_null
545 ; CHECK-NEXT: movl $42, %eax
549 %c = icmp eq ptr %x, null
550 br i1 %c, label %is_null, label %not_null, !make.implicit !0
556 %x.gep = getelementptr i32, ptr %x, i32 -32
557 %t = load i32, ptr %x.gep
561 ; This redefines the null check reg by doing a zero-extend and a shift on
563 ; Converted into implicit null check since both of these operations do not
564 ; change the nullness of %x (i.e. if it is null, it remains null).
565 define i64 @imp_null_check_load_shift_addr(ptr %x) {
566 ; CHECK-LABEL: imp_null_check_load_shift_addr:
567 ; CHECK: ## %bb.0: ## %entry
568 ; CHECK-NEXT: shlq $6, %rdi
569 ; CHECK-NEXT: Ltmp17:
570 ; CHECK-NEXT: movq 8(%rdi), %rax ## on-fault: LBB21_1
571 ; CHECK-NEXT: ## %bb.2: ## %not_null
573 ; CHECK-NEXT: LBB21_1: ## %is_null
574 ; CHECK-NEXT: movl $42, %eax
578 %c = icmp eq ptr %x, null
579 br i1 %c, label %is_null, label %not_null, !make.implicit !0
585 %y = ptrtoint ptr %x to i64
586 %shry = shl i64 %y, 6
587 %y.ptr = inttoptr i64 %shry to ptr
588 %x.loc = getelementptr i64, ptr %y.ptr, i64 1
589 %t = load i64, ptr %x.loc
593 ; Same as imp_null_check_load_shift_addr but shift is by 3 and this is now
594 ; converted into complex addressing.
595 define i64 @imp_null_check_load_shift_by_3_addr(ptr %x) {
596 ; CHECK-LABEL: imp_null_check_load_shift_by_3_addr:
597 ; CHECK: ## %bb.0: ## %entry
598 ; CHECK-NEXT: Ltmp18:
599 ; CHECK-NEXT: movq 8(,%rdi,8), %rax ## on-fault: LBB22_1
600 ; CHECK-NEXT: ## %bb.2: ## %not_null
602 ; CHECK-NEXT: LBB22_1: ## %is_null
603 ; CHECK-NEXT: movl $42, %eax
607 %c = icmp eq ptr %x, null
608 br i1 %c, label %is_null, label %not_null, !make.implicit !0
614 %y = ptrtoint ptr %x to i64
615 %shry = shl i64 %y, 3
616 %y.ptr = inttoptr i64 %shry to ptr
617 %x.loc = getelementptr i64, ptr %y.ptr, i64 1
618 %t = load i64, ptr %x.loc
622 define i64 @imp_null_check_load_shift_add_addr(ptr %x) {
623 ; CHECK-LABEL: imp_null_check_load_shift_add_addr:
624 ; CHECK: ## %bb.0: ## %entry
625 ; CHECK: movq 3526(,%rdi,8), %rax ## on-fault: LBB23_1
626 ; CHECK-NEXT: ## %bb.2: ## %not_null
628 ; CHECK-NEXT: LBB23_1: ## %is_null
629 ; CHECK-NEXT: movl $42, %eax
633 %c = icmp eq ptr %x, null
634 br i1 %c, label %is_null, label %not_null, !make.implicit !0
640 %y = ptrtoint ptr %x to i64
641 %shry = shl i64 %y, 3
642 %shry.add = add i64 %shry, 3518
643 %y.ptr = inttoptr i64 %shry.add to ptr
644 %x.loc = getelementptr i64, ptr %y.ptr, i64 1
645 %t = load i64, ptr %x.loc