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