1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=aarch64-unknown-linux-gnu --aarch64-enable-sink-fold=true < %s | FileCheck %s 3 4; Fold 5; ptr - (ptr & (alignment-1)) 6; To 7; ptr & (0 - alignment) 8; 9; This needs to be a backend-level fold because only by now pointers 10; are just registers; in middle-end IR this can only be done via @llvm.ptrmask() 11; intrinsic which is not sufficiently widely-spread yet. 12; 13; https://bugs.llvm.org/show_bug.cgi?id=44448 14 15; The basic positive tests 16 17define i32 @t0_32(i32 %ptr, i32 %alignment) nounwind { 18; CHECK-LABEL: t0_32: 19; CHECK: // %bb.0: 20; CHECK-NEXT: neg w8, w1 21; CHECK-NEXT: and w0, w0, w8 22; CHECK-NEXT: ret 23 %mask = add i32 %alignment, -1 24 %bias = and i32 %ptr, %mask 25 %r = sub i32 %ptr, %bias 26 ret i32 %r 27} 28define i64 @t1_64(i64 %ptr, i64 %alignment) nounwind { 29; CHECK-LABEL: t1_64: 30; CHECK: // %bb.0: 31; CHECK-NEXT: neg x8, x1 32; CHECK-NEXT: and x0, x0, x8 33; CHECK-NEXT: ret 34 %mask = add i64 %alignment, -1 35 %bias = and i64 %ptr, %mask 36 %r = sub i64 %ptr, %bias 37 ret i64 %r 38} 39 40define i32 @t2_commutative(i32 %ptr, i32 %alignment) nounwind { 41; CHECK-LABEL: t2_commutative: 42; CHECK: // %bb.0: 43; CHECK-NEXT: neg w8, w1 44; CHECK-NEXT: and w0, w0, w8 45; CHECK-NEXT: ret 46 %mask = add i32 %alignment, -1 47 %bias = and i32 %mask, %ptr ; swapped 48 %r = sub i32 %ptr, %bias 49 ret i32 %r 50} 51 52; Extra use tests 53 54define i32 @t3_extrause0(i32 %ptr, i32 %alignment, ptr %mask_storage) nounwind { 55; CHECK-LABEL: t3_extrause0: 56; CHECK: // %bb.0: 57; CHECK-NEXT: neg w8, w1 58; CHECK-NEXT: sub w9, w1, #1 59; CHECK-NEXT: and w0, w0, w8 60; CHECK-NEXT: str w9, [x2] 61; CHECK-NEXT: ret 62 %mask = add i32 %alignment, -1 63 store i32 %mask, ptr %mask_storage 64 %bias = and i32 %ptr, %mask 65 %r = sub i32 %ptr, %bias 66 ret i32 %r 67} 68define i32 @n4_extrause1(i32 %ptr, i32 %alignment, ptr %bias_storage) nounwind { 69; CHECK-LABEL: n4_extrause1: 70; CHECK: // %bb.0: 71; CHECK-NEXT: sub w8, w1, #1 72; CHECK-NEXT: and w8, w0, w8 73; CHECK-NEXT: sub w0, w0, w8 74; CHECK-NEXT: str w8, [x2] 75; CHECK-NEXT: ret 76 %mask = add i32 %alignment, -1 77 %bias = and i32 %ptr, %mask ; has extra uses, can't fold 78 store i32 %bias, ptr %bias_storage 79 %r = sub i32 %ptr, %bias 80 ret i32 %r 81} 82define i32 @n5_extrause2(i32 %ptr, i32 %alignment, ptr %mask_storage, ptr %bias_storage) nounwind { 83; CHECK-LABEL: n5_extrause2: 84; CHECK: // %bb.0: 85; CHECK-NEXT: sub w8, w1, #1 86; CHECK-NEXT: and w9, w0, w8 87; CHECK-NEXT: str w8, [x2] 88; CHECK-NEXT: sub w0, w0, w9 89; CHECK-NEXT: str w9, [x3] 90; CHECK-NEXT: ret 91 %mask = add i32 %alignment, -1 92 store i32 %mask, ptr %mask_storage 93 %bias = and i32 %ptr, %mask ; has extra uses, can't fold 94 store i32 %bias, ptr %bias_storage 95 %r = sub i32 %ptr, %bias 96 ret i32 %r 97} 98 99; Negative tests 100 101define i32 @n6_different_ptrs(i32 %ptr0, i32 %ptr1, i32 %alignment) nounwind { 102; CHECK-LABEL: n6_different_ptrs: 103; CHECK: // %bb.0: 104; CHECK-NEXT: sub w8, w2, #1 105; CHECK-NEXT: and w8, w1, w8 106; CHECK-NEXT: sub w0, w0, w8 107; CHECK-NEXT: ret 108 %mask = add i32 %alignment, -1 109 %bias = and i32 %ptr1, %mask ; not %ptr0 110 %r = sub i32 %ptr0, %bias ; not %ptr1 111 ret i32 %r 112} 113define i32 @n7_different_ptrs_commutative(i32 %ptr0, i32 %ptr1, i32 %alignment) nounwind { 114; CHECK-LABEL: n7_different_ptrs_commutative: 115; CHECK: // %bb.0: 116; CHECK-NEXT: sub w8, w2, #1 117; CHECK-NEXT: and w8, w8, w1 118; CHECK-NEXT: sub w0, w0, w8 119; CHECK-NEXT: ret 120 %mask = add i32 %alignment, -1 121 %bias = and i32 %mask, %ptr1 ; swapped, not %ptr0 122 %r = sub i32 %ptr0, %bias ; not %ptr1 123 ret i32 %r 124} 125 126define i32 @n8_not_lowbit_mask(i32 %ptr, i32 %alignment) nounwind { 127; CHECK-LABEL: n8_not_lowbit_mask: 128; CHECK: // %bb.0: 129; CHECK-NEXT: add w8, w1, #1 130; CHECK-NEXT: bic w0, w0, w8 131; CHECK-NEXT: ret 132 %mask = add i32 %alignment, 1 ; not -1 133 %bias = and i32 %ptr, %mask 134 %r = sub i32 %ptr, %bias 135 ret i32 %r 136} 137 138define i32 @n9_sub_is_not_commutative(i32 %ptr, i32 %alignment) nounwind { 139; CHECK-LABEL: n9_sub_is_not_commutative: 140; CHECK: // %bb.0: 141; CHECK-NEXT: sub w8, w1, #1 142; CHECK-NEXT: and w8, w0, w8 143; CHECK-NEXT: sub w0, w8, w0 144; CHECK-NEXT: ret 145 %mask = add i32 %alignment, -1 146 %bias = and i32 %ptr, %mask 147 %r = sub i32 %bias, %ptr ; wrong order 148 ret i32 %r 149} 150