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