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