brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.6 KiB · 052ff7f Raw
428 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc < %s -verify-machineinstrs -O3 -mtriple=aarch64-unknown-unknown -enable-implicit-null-checks | FileCheck %s3 4; Basic test for implicit null check conversion - this is analogous to the5; file with the same name in the X86 tree, but adjusted to remove patterns6; related to memory folding of arithmetic (since aarch64 doesn't), and add7; a couple of aarch64 specific tests.8 9define i32 @imp_null_check_load_fallthrough(ptr %x) {10; CHECK-LABEL: imp_null_check_load_fallthrough:11; CHECK:       // %bb.0: // %entry12; CHECK-NEXT:  .Ltmp0:13; CHECK-NEXT:    ldr w0, [x0] // on-fault: .LBB0_214; CHECK-NEXT:  // %bb.1: // %not_null15; CHECK-NEXT:    ret16; CHECK-NEXT:  .LBB0_2:17; CHECK-NEXT:    mov w0, #4218; CHECK-NEXT:    ret19 entry:20  %c = icmp eq ptr %x, null21  br i1 %c, label %is_null, label %not_null, !make.implicit !022 23 not_null:24  %t = load i32, ptr %x25  ret i32 %t26 27is_null:28  ret i32 4229}30 31 32define i32 @imp_null_check_load_reorder(ptr %x) {33; CHECK-LABEL: imp_null_check_load_reorder:34; CHECK:       // %bb.0: // %entry35; CHECK-NEXT:  .Ltmp1:36; CHECK-NEXT:    ldr w0, [x0] // on-fault: .LBB1_237; CHECK-NEXT:  // %bb.1: // %not_null38; CHECK-NEXT:    ret39; CHECK-NEXT:  .LBB1_2:40; CHECK-NEXT:    mov w0, #4241; CHECK-NEXT:    ret42 entry:43  %c = icmp eq ptr %x, null44  br i1 %c, label %is_null, label %not_null, !make.implicit !045 46 is_null:47  ret i32 4248 49 not_null:50  %t = load i32, ptr %x51  ret i32 %t52}53 54define i32 @imp_null_check_unordered_load(ptr %x) {55; CHECK-LABEL: imp_null_check_unordered_load:56; CHECK:       // %bb.0: // %entry57; CHECK-NEXT:  .Ltmp2:58; CHECK-NEXT:    ldr w0, [x0] // on-fault: .LBB2_259; CHECK-NEXT:  // %bb.1: // %not_null60; CHECK-NEXT:    ret61; CHECK-NEXT:  .LBB2_2:62; CHECK-NEXT:    mov w0, #4263; CHECK-NEXT:    ret64 entry:65  %c = icmp eq ptr %x, null66  br i1 %c, label %is_null, label %not_null, !make.implicit !067 68 is_null:69  ret i32 4270 71 not_null:72  %t = load atomic i32, ptr %x unordered, align 473  ret i32 %t74}75 76 77; TODO: Can be converted into implicit check.78;; Probably could be implicit, but we're conservative for now79define i32 @imp_null_check_seq_cst_load(ptr %x) {80; CHECK-LABEL: imp_null_check_seq_cst_load:81; CHECK:       // %bb.0: // %entry82; CHECK-NEXT:    cbz x0, .LBB3_283; CHECK-NEXT:  // %bb.1: // %not_null84; CHECK-NEXT:    ldar w0, [x0]85; CHECK-NEXT:    ret86; CHECK-NEXT:  .LBB3_2:87; CHECK-NEXT:    mov w0, #4288; CHECK-NEXT:    ret89 entry:90  %c = icmp eq ptr %x, null91  br i1 %c, label %is_null, label %not_null, !make.implicit !092 93 is_null:94  ret i32 4295 96 not_null:97  %t = load atomic i32, ptr %x seq_cst, align 498  ret i32 %t99}100 101;; Might be memory mapped IO, so can't rely on fault behavior102define i32 @imp_null_check_volatile_load(ptr %x) {103; CHECK-LABEL: imp_null_check_volatile_load:104; CHECK:       // %bb.0: // %entry105; CHECK-NEXT:    cbz x0, .LBB4_2106; CHECK-NEXT:  // %bb.1: // %not_null107; CHECK-NEXT:    ldr w0, [x0]108; CHECK-NEXT:    ret109; CHECK-NEXT:  .LBB4_2:110; CHECK-NEXT:    mov w0, #42111; CHECK-NEXT:    ret112 entry:113  %c = icmp eq ptr %x, null114  br i1 %c, label %is_null, label %not_null, !make.implicit !0115 116 is_null:117  ret i32 42118 119 not_null:120  %t = load volatile i32, ptr %x, align 4121  ret i32 %t122}123 124 125define i8 @imp_null_check_load_i8(ptr %x) {126; CHECK-LABEL: imp_null_check_load_i8:127; CHECK:       // %bb.0: // %entry128; CHECK-NEXT:  .Ltmp3:129; CHECK-NEXT:    ldrb w0, [x0] // on-fault: .LBB5_2130; CHECK-NEXT:  // %bb.1: // %not_null131; CHECK-NEXT:    ret132; CHECK-NEXT:  .LBB5_2:133; CHECK-NEXT:    mov w0, #42134; CHECK-NEXT:    ret135 entry:136  %c = icmp eq ptr %x, null137  br i1 %c, label %is_null, label %not_null, !make.implicit !0138 139 is_null:140  ret i8 42141 142 not_null:143  %t = load i8, ptr %x144  ret i8 %t145}146 147define i256 @imp_null_check_load_i256(ptr %x) {148; CHECK-LABEL: imp_null_check_load_i256:149; CHECK:       // %bb.0: // %entry150; CHECK-NEXT:    cbz x0, .LBB6_2151; CHECK-NEXT:  // %bb.1: // %not_null152; CHECK-NEXT:    ldp x2, x3, [x0, #16]153; CHECK-NEXT:    ldp x0, x1, [x0]154; CHECK-NEXT:    ret155; CHECK-NEXT:  .LBB6_2:156; CHECK-NEXT:    mov x1, xzr157; CHECK-NEXT:    mov x2, xzr158; CHECK-NEXT:    mov x3, xzr159; CHECK-NEXT:    mov w0, #42160; CHECK-NEXT:    ret161 entry:162  %c = icmp eq ptr %x, null163  br i1 %c, label %is_null, label %not_null, !make.implicit !0164 165 is_null:166  ret i256 42167 168 not_null:169  %t = load i256, ptr %x170  ret i256 %t171}172 173 174 175define i32 @imp_null_check_gep_load(ptr %x) {176; CHECK-LABEL: imp_null_check_gep_load:177; CHECK:       // %bb.0: // %entry178; CHECK-NEXT:  .Ltmp4:179; CHECK-NEXT:    ldr w0, [x0, #128] // on-fault: .LBB7_2180; CHECK-NEXT:  // %bb.1: // %not_null181; CHECK-NEXT:    ret182; CHECK-NEXT:  .LBB7_2:183; CHECK-NEXT:    mov w0, #42184; CHECK-NEXT:    ret185 entry:186  %c = icmp eq ptr %x, null187  br i1 %c, label %is_null, label %not_null, !make.implicit !0188 189 is_null:190  ret i32 42191 192 not_null:193  %x.gep = getelementptr i32, ptr %x, i32 32194  %t = load i32, ptr %x.gep195  ret i32 %t196}197 198define i32 @imp_null_check_add_result(ptr %x, i32 %p) {199; CHECK-LABEL: imp_null_check_add_result:200; CHECK:       // %bb.0: // %entry201; CHECK-NEXT:  .Ltmp5:202; CHECK-NEXT:    ldr w8, [x0] // on-fault: .LBB8_2203; CHECK-NEXT:  // %bb.1: // %not_null204; CHECK-NEXT:    add w0, w8, w1205; CHECK-NEXT:    ret206; CHECK-NEXT:  .LBB8_2:207; CHECK-NEXT:    mov w0, #42208; CHECK-NEXT:    ret209 entry:210  %c = icmp eq ptr %x, null211  br i1 %c, label %is_null, label %not_null, !make.implicit !0212 213 is_null:214  ret i32 42215 216 not_null:217  %t = load i32, ptr %x218  %p1 = add i32 %t, %p219  ret i32 %p1220}221 222; Can hoist over a potential faulting instruction as long as we don't223; change the conditions under which the instruction faults.224define i32 @imp_null_check_hoist_over_udiv(ptr %x, i32 %a, i32 %b) {225; CHECK-LABEL: imp_null_check_hoist_over_udiv:226; CHECK:       // %bb.0: // %entry227; CHECK-NEXT:    cbz x0, .LBB9_2228; CHECK-NEXT:  // %bb.1: // %not_null229; CHECK-NEXT:    udiv w8, w1, w2230; CHECK-NEXT:    ldr w9, [x0]231; CHECK-NEXT:    add w0, w9, w8232; CHECK-NEXT:    ret233; CHECK-NEXT:  .LBB9_2:234; CHECK-NEXT:    mov w0, #42235; CHECK-NEXT:    ret236 entry:237  %c = icmp eq ptr %x, null238  br i1 %c, label %is_null, label %not_null, !make.implicit !0239 240 is_null:241  ret i32 42242 243 not_null:244  %p1 = udiv i32 %a, %b245  %t = load i32, ptr %x246  %res = add i32 %t, %p1247  ret i32 %res248}249 250 251; TODO: We should be able to hoist this - we can on x86, why isn't this252; working for aarch64?  Aliasing?253define i32 @imp_null_check_hoist_over_unrelated_load(ptr %x, ptr %y, ptr %z) {254; CHECK-LABEL: imp_null_check_hoist_over_unrelated_load:255; CHECK:       // %bb.0: // %entry256; CHECK-NEXT:    cbz x0, .LBB10_2257; CHECK-NEXT:  // %bb.1: // %not_null258; CHECK-NEXT:    ldr w8, [x1]259; CHECK-NEXT:    ldr w0, [x0]260; CHECK-NEXT:    str w8, [x2]261; CHECK-NEXT:    ret262; CHECK-NEXT:  .LBB10_2:263; CHECK-NEXT:    mov w0, #42264; CHECK-NEXT:    ret265 entry:266  %c = icmp eq ptr %x, null267  br i1 %c, label %is_null, label %not_null, !make.implicit !0268 269 is_null:270  ret i32 42271 272 not_null:273  %t0 = load i32, ptr %y274  %t1 = load i32, ptr %x275  store i32 %t0, ptr %z276  ret i32 %t1277}278 279define i32 @imp_null_check_gep_load_with_use_dep(ptr %x, i32 %a) {280; CHECK-LABEL: imp_null_check_gep_load_with_use_dep:281; CHECK:       // %bb.0: // %entry282; CHECK-NEXT:  .Ltmp6:283; CHECK-NEXT:    ldr w8, [x0] // on-fault: .LBB11_2284; CHECK-NEXT:  // %bb.1: // %not_null285; CHECK-NEXT:    add w9, w0, w1286; CHECK-NEXT:    add w8, w9, w8287; CHECK-NEXT:    add w0, w8, #4288; CHECK-NEXT:    ret289; CHECK-NEXT:  .LBB11_2:290; CHECK-NEXT:    mov w0, #42291; CHECK-NEXT:    ret292 entry:293  %c = icmp eq ptr %x, null294  br i1 %c, label %is_null, label %not_null, !make.implicit !0295 296 is_null:297  ret i32 42298 299 not_null:300  %x.loc = getelementptr i32, ptr %x, i32 1301  %y = ptrtoint ptr %x.loc to i32302  %b = add i32 %a, %y303  %t = load i32, ptr %x304  %z = add i32 %t, %b305  ret i32 %z306}307 308;; TODO: We could handle this case as we can lift the fence into the309;; previous block before the conditional without changing behavior.310define i32 @imp_null_check_load_fence1(ptr %x) {311; CHECK-LABEL: imp_null_check_load_fence1:312; CHECK:       // %bb.0: // %entry313; CHECK-NEXT:    cbz x0, .LBB12_2314; CHECK-NEXT:  // %bb.1: // %not_null315; CHECK-NEXT:    dmb ishld316; CHECK-NEXT:    ldr w0, [x0]317; CHECK-NEXT:    ret318; CHECK-NEXT:  .LBB12_2:319; CHECK-NEXT:    mov w0, #42320; CHECK-NEXT:    ret321entry:322  %c = icmp eq ptr %x, null323  br i1 %c, label %is_null, label %not_null, !make.implicit !0324 325is_null:326  ret i32 42327 328not_null:329  fence acquire330  %t = load i32, ptr %x331  ret i32 %t332}333 334;; TODO: We could handle this case as we can lift the fence into the335;; previous block before the conditional without changing behavior.336define i32 @imp_null_check_load_fence2(ptr %x) {337; CHECK-LABEL: imp_null_check_load_fence2:338; CHECK:       // %bb.0: // %entry339; CHECK-NEXT:    cbz x0, .LBB13_2340; CHECK-NEXT:  // %bb.1: // %not_null341; CHECK-NEXT:    dmb ish342; CHECK-NEXT:    ldr w0, [x0]343; CHECK-NEXT:    ret344; CHECK-NEXT:  .LBB13_2:345; CHECK-NEXT:    mov w0, #42346; CHECK-NEXT:    ret347entry:348  %c = icmp eq ptr %x, null349  br i1 %c, label %is_null, label %not_null, !make.implicit !0350 351is_null:352  ret i32 42353 354not_null:355  fence seq_cst356  %t = load i32, ptr %x357  ret i32 %t358}359 360; TODO: We can fold to implicit null here, not sure why this isn't working361define void @imp_null_check_store(ptr %x) {362; CHECK-LABEL: imp_null_check_store:363; CHECK:       // %bb.0: // %entry364; CHECK-NEXT:    cbz x0, .LBB14_2365; CHECK-NEXT:  // %bb.1: // %not_null366; CHECK-NEXT:    mov w8, #1367; CHECK-NEXT:    str w8, [x0]368; CHECK-NEXT:  .LBB14_2: // %common.ret369; CHECK-NEXT:    ret370 entry:371  %c = icmp eq ptr %x, null372  br i1 %c, label %is_null, label %not_null, !make.implicit !0373 374 is_null:375  ret void376 377 not_null:378  store i32 1, ptr %x379  ret void380}381 382;; TODO: can be implicit383define void @imp_null_check_unordered_store(ptr %x) {384; CHECK-LABEL: imp_null_check_unordered_store:385; CHECK:       // %bb.0: // %entry386; CHECK-NEXT:    cbz x0, .LBB15_2387; CHECK-NEXT:  // %bb.1: // %not_null388; CHECK-NEXT:    mov w8, #1389; CHECK-NEXT:    str w8, [x0]390; CHECK-NEXT:  .LBB15_2: // %common.ret391; CHECK-NEXT:    ret392 entry:393  %c = icmp eq ptr %x, null394  br i1 %c, label %is_null, label %not_null, !make.implicit !0395 396 is_null:397  ret void398 399 not_null:400  store atomic i32 1, ptr %x unordered, align 4401  ret void402}403 404define i32 @imp_null_check_neg_gep_load(ptr %x) {405; CHECK-LABEL: imp_null_check_neg_gep_load:406; CHECK:       // %bb.0: // %entry407; CHECK-NEXT:  .Ltmp7:408; CHECK-NEXT:    ldur w0, [x0, #-128] // on-fault: .LBB16_2409; CHECK-NEXT:  // %bb.1: // %not_null410; CHECK-NEXT:    ret411; CHECK-NEXT:  .LBB16_2:412; CHECK-NEXT:    mov w0, #42413; CHECK-NEXT:    ret414 entry:415  %c = icmp eq ptr %x, null416  br i1 %c, label %is_null, label %not_null, !make.implicit !0417 418 is_null:419  ret i32 42420 421 not_null:422  %x.gep = getelementptr i32, ptr %x, i32 -32423  %t = load i32, ptr %x.gep424  ret i32 %t425}426 427!0 = !{}428