1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=aarch64-unknown-unknown < %s | FileCheck %s --check-prefix=CHECK 3 4; We are looking for the following pattern here: 5; (X & (C << Y)) ==/!= 0 6; It may be optimal to hoist the constant: 7; ((X l>> Y) & C) ==/!= 0 8 9;------------------------------------------------------------------------------; 10; A few scalar test 11;------------------------------------------------------------------------------; 12 13; i8 scalar 14 15define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind { 16; CHECK-LABEL: scalar_i8_signbit_eq: 17; CHECK: // %bb.0: 18; CHECK-NEXT: and w8, w0, #0xff 19; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 20; CHECK-NEXT: lsr w8, w8, w1 21; CHECK-NEXT: tst w8, #0x80 22; CHECK-NEXT: cset w0, eq 23; CHECK-NEXT: ret 24 %t0 = shl i8 128, %y 25 %t1 = and i8 %t0, %x 26 %res = icmp eq i8 %t1, 0 27 ret i1 %res 28} 29 30define i1 @scalar_i8_lowestbit_eq(i8 %x, i8 %y) nounwind { 31; CHECK-LABEL: scalar_i8_lowestbit_eq: 32; CHECK: // %bb.0: 33; CHECK-NEXT: and w8, w0, #0xff 34; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 35; CHECK-NEXT: lsr w8, w8, w1 36; CHECK-NEXT: tst w8, #0x1 37; CHECK-NEXT: cset w0, eq 38; CHECK-NEXT: ret 39 %t0 = shl i8 1, %y 40 %t1 = and i8 %t0, %x 41 %res = icmp eq i8 %t1, 0 42 ret i1 %res 43} 44 45define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind { 46; CHECK-LABEL: scalar_i8_bitsinmiddle_eq: 47; CHECK: // %bb.0: 48; CHECK-NEXT: and w8, w0, #0xff 49; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 50; CHECK-NEXT: lsr w8, w8, w1 51; CHECK-NEXT: tst w8, #0x18 52; CHECK-NEXT: cset w0, eq 53; CHECK-NEXT: ret 54 %t0 = shl i8 24, %y 55 %t1 = and i8 %t0, %x 56 %res = icmp eq i8 %t1, 0 57 ret i1 %res 58} 59 60; i16 scalar 61 62define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind { 63; CHECK-LABEL: scalar_i16_signbit_eq: 64; CHECK: // %bb.0: 65; CHECK-NEXT: and w8, w0, #0xffff 66; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 67; CHECK-NEXT: lsr w8, w8, w1 68; CHECK-NEXT: tst w8, #0x8000 69; CHECK-NEXT: cset w0, eq 70; CHECK-NEXT: ret 71 %t0 = shl i16 32768, %y 72 %t1 = and i16 %t0, %x 73 %res = icmp eq i16 %t1, 0 74 ret i1 %res 75} 76 77define i1 @scalar_i16_lowestbit_eq(i16 %x, i16 %y) nounwind { 78; CHECK-LABEL: scalar_i16_lowestbit_eq: 79; CHECK: // %bb.0: 80; CHECK-NEXT: and w8, w0, #0xffff 81; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 82; CHECK-NEXT: lsr w8, w8, w1 83; CHECK-NEXT: tst w8, #0x1 84; CHECK-NEXT: cset w0, eq 85; CHECK-NEXT: ret 86 %t0 = shl i16 1, %y 87 %t1 = and i16 %t0, %x 88 %res = icmp eq i16 %t1, 0 89 ret i1 %res 90} 91 92define i1 @scalar_i16_bitsinmiddle_eq(i16 %x, i16 %y) nounwind { 93; CHECK-LABEL: scalar_i16_bitsinmiddle_eq: 94; CHECK: // %bb.0: 95; CHECK-NEXT: and w8, w0, #0xffff 96; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 97; CHECK-NEXT: lsr w8, w8, w1 98; CHECK-NEXT: tst w8, #0xff0 99; CHECK-NEXT: cset w0, eq 100; CHECK-NEXT: ret 101 %t0 = shl i16 4080, %y 102 %t1 = and i16 %t0, %x 103 %res = icmp eq i16 %t1, 0 104 ret i1 %res 105} 106 107; i32 scalar 108 109define i1 @scalar_i32_signbit_eq(i32 %x, i32 %y) nounwind { 110; CHECK-LABEL: scalar_i32_signbit_eq: 111; CHECK: // %bb.0: 112; CHECK-NEXT: lsr w8, w0, w1 113; CHECK-NEXT: tst w8, #0x80000000 114; CHECK-NEXT: cset w0, eq 115; CHECK-NEXT: ret 116 %t0 = shl i32 2147483648, %y 117 %t1 = and i32 %t0, %x 118 %res = icmp eq i32 %t1, 0 119 ret i1 %res 120} 121 122define i1 @scalar_i32_lowestbit_eq(i32 %x, i32 %y) nounwind { 123; CHECK-LABEL: scalar_i32_lowestbit_eq: 124; CHECK: // %bb.0: 125; CHECK-NEXT: lsr w8, w0, w1 126; CHECK-NEXT: tst w8, #0x1 127; CHECK-NEXT: cset w0, eq 128; CHECK-NEXT: ret 129 %t0 = shl i32 1, %y 130 %t1 = and i32 %t0, %x 131 %res = icmp eq i32 %t1, 0 132 ret i1 %res 133} 134 135define i1 @scalar_i32_bitsinmiddle_eq(i32 %x, i32 %y) nounwind { 136; CHECK-LABEL: scalar_i32_bitsinmiddle_eq: 137; CHECK: // %bb.0: 138; CHECK-NEXT: lsr w8, w0, w1 139; CHECK-NEXT: tst w8, #0xffff00 140; CHECK-NEXT: cset w0, eq 141; CHECK-NEXT: ret 142 %t0 = shl i32 16776960, %y 143 %t1 = and i32 %t0, %x 144 %res = icmp eq i32 %t1, 0 145 ret i1 %res 146} 147 148; i64 scalar 149 150define i1 @scalar_i64_signbit_eq(i64 %x, i64 %y) nounwind { 151; CHECK-LABEL: scalar_i64_signbit_eq: 152; CHECK: // %bb.0: 153; CHECK-NEXT: lsr x8, x0, x1 154; CHECK-NEXT: tst x8, #0x8000000000000000 155; CHECK-NEXT: cset w0, eq 156; CHECK-NEXT: ret 157 %t0 = shl i64 9223372036854775808, %y 158 %t1 = and i64 %t0, %x 159 %res = icmp eq i64 %t1, 0 160 ret i1 %res 161} 162 163define i1 @scalar_i64_lowestbit_eq(i64 %x, i64 %y) nounwind { 164; CHECK-LABEL: scalar_i64_lowestbit_eq: 165; CHECK: // %bb.0: 166; CHECK-NEXT: lsr x8, x0, x1 167; CHECK-NEXT: tst x8, #0x1 168; CHECK-NEXT: cset w0, eq 169; CHECK-NEXT: ret 170 %t0 = shl i64 1, %y 171 %t1 = and i64 %t0, %x 172 %res = icmp eq i64 %t1, 0 173 ret i1 %res 174} 175 176define i1 @scalar_i64_bitsinmiddle_eq(i64 %x, i64 %y) nounwind { 177; CHECK-LABEL: scalar_i64_bitsinmiddle_eq: 178; CHECK: // %bb.0: 179; CHECK-NEXT: lsr x8, x0, x1 180; CHECK-NEXT: tst x8, #0xffffffff0000 181; CHECK-NEXT: cset w0, eq 182; CHECK-NEXT: ret 183 %t0 = shl i64 281474976645120, %y 184 %t1 = and i64 %t0, %x 185 %res = icmp eq i64 %t1, 0 186 ret i1 %res 187} 188 189;------------------------------------------------------------------------------; 190; A few trivial vector tests 191;------------------------------------------------------------------------------; 192 193define <4 x i1> @vec_4xi32_splat_eq(<4 x i32> %x, <4 x i32> %y) nounwind { 194; CHECK-LABEL: vec_4xi32_splat_eq: 195; CHECK: // %bb.0: 196; CHECK-NEXT: movi v2.4s, #1 197; CHECK-NEXT: ushl v1.4s, v2.4s, v1.4s 198; CHECK-NEXT: and v0.16b, v1.16b, v0.16b 199; CHECK-NEXT: cmeq v0.4s, v0.4s, #0 200; CHECK-NEXT: xtn v0.4h, v0.4s 201; CHECK-NEXT: ret 202 %t0 = shl <4 x i32> <i32 1, i32 1, i32 1, i32 1>, %y 203 %t1 = and <4 x i32> %t0, %x 204 %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 0, i32 0> 205 ret <4 x i1> %res 206} 207 208define <4 x i1> @vec_4xi32_nonsplat_eq(<4 x i32> %x, <4 x i32> %y) nounwind { 209; CHECK-LABEL: vec_4xi32_nonsplat_eq: 210; CHECK: // %bb.0: 211; CHECK-NEXT: adrp x8, .LCPI13_0 212; CHECK-NEXT: ldr q2, [x8, :lo12:.LCPI13_0] 213; CHECK-NEXT: ushl v1.4s, v2.4s, v1.4s 214; CHECK-NEXT: and v0.16b, v1.16b, v0.16b 215; CHECK-NEXT: cmeq v0.4s, v0.4s, #0 216; CHECK-NEXT: xtn v0.4h, v0.4s 217; CHECK-NEXT: ret 218 %t0 = shl <4 x i32> <i32 0, i32 1, i32 16776960, i32 2147483648>, %y 219 %t1 = and <4 x i32> %t0, %x 220 %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 0, i32 0> 221 ret <4 x i1> %res 222} 223 224define <4 x i1> @vec_4xi32_nonsplat_undef0_eq(<4 x i32> %x, <4 x i32> %y) nounwind { 225; CHECK-LABEL: vec_4xi32_nonsplat_undef0_eq: 226; CHECK: // %bb.0: 227; CHECK-NEXT: movi v2.4s, #1 228; CHECK-NEXT: ushl v1.4s, v2.4s, v1.4s 229; CHECK-NEXT: and v0.16b, v1.16b, v0.16b 230; CHECK-NEXT: cmeq v0.4s, v0.4s, #0 231; CHECK-NEXT: xtn v0.4h, v0.4s 232; CHECK-NEXT: ret 233 %t0 = shl <4 x i32> <i32 1, i32 1, i32 undef, i32 1>, %y 234 %t1 = and <4 x i32> %t0, %x 235 %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 0, i32 0> 236 ret <4 x i1> %res 237} 238define <4 x i1> @vec_4xi32_nonsplat_undef1_eq(<4 x i32> %x, <4 x i32> %y) nounwind { 239; CHECK-LABEL: vec_4xi32_nonsplat_undef1_eq: 240; CHECK: // %bb.0: 241; CHECK-NEXT: movi v2.4s, #1 242; CHECK-NEXT: ushl v1.4s, v2.4s, v1.4s 243; CHECK-NEXT: and v0.16b, v1.16b, v0.16b 244; CHECK-NEXT: cmeq v0.4s, v0.4s, #0 245; CHECK-NEXT: xtn v0.4h, v0.4s 246; CHECK-NEXT: ret 247 %t0 = shl <4 x i32> <i32 1, i32 1, i32 1, i32 1>, %y 248 %t1 = and <4 x i32> %t0, %x 249 %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 undef, i32 0> 250 ret <4 x i1> %res 251} 252define <4 x i1> @vec_4xi32_nonsplat_undef2_eq(<4 x i32> %x, <4 x i32> %y) nounwind { 253; CHECK-LABEL: vec_4xi32_nonsplat_undef2_eq: 254; CHECK: // %bb.0: 255; CHECK-NEXT: movi v2.4s, #1 256; CHECK-NEXT: ushl v1.4s, v2.4s, v1.4s 257; CHECK-NEXT: and v0.16b, v1.16b, v0.16b 258; CHECK-NEXT: cmeq v0.4s, v0.4s, #0 259; CHECK-NEXT: xtn v0.4h, v0.4s 260; CHECK-NEXT: ret 261 %t0 = shl <4 x i32> <i32 1, i32 1, i32 undef, i32 1>, %y 262 %t1 = and <4 x i32> %t0, %x 263 %res = icmp eq <4 x i32> %t1, <i32 0, i32 0, i32 undef, i32 0> 264 ret <4 x i1> %res 265} 266 267;------------------------------------------------------------------------------; 268; A special tests 269;------------------------------------------------------------------------------; 270 271define i1 @scalar_i8_signbit_ne(i8 %x, i8 %y) nounwind { 272; CHECK-LABEL: scalar_i8_signbit_ne: 273; CHECK: // %bb.0: 274; CHECK-NEXT: and w8, w0, #0xff 275; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 276; CHECK-NEXT: lsr w8, w8, w1 277; CHECK-NEXT: lsr w0, w8, #7 278; CHECK-NEXT: ret 279 %t0 = shl i8 128, %y 280 %t1 = and i8 %t0, %x 281 %res = icmp ne i8 %t1, 0 ; we are perfectly happy with 'ne' predicate 282 ret i1 %res 283} 284 285;------------------------------------------------------------------------------; 286; What if X is a constant too? 287;------------------------------------------------------------------------------; 288 289define i1 @scalar_i32_x_is_const_eq(i32 %y) nounwind { 290; CHECK-LABEL: scalar_i32_x_is_const_eq: 291; CHECK: // %bb.0: 292; CHECK-NEXT: mov w8, #43605 293; CHECK-NEXT: movk w8, #43605, lsl #16 294; CHECK-NEXT: lsl w8, w8, w0 295; CHECK-NEXT: tst w8, #0x1 296; CHECK-NEXT: cset w0, eq 297; CHECK-NEXT: ret 298 %t0 = shl i32 2857740885, %y 299 %t1 = and i32 %t0, 1 300 %res = icmp eq i32 %t1, 0 301 ret i1 %res 302} 303define i1 @scalar_i32_x_is_const2_eq(i32 %y) nounwind { 304; CHECK-LABEL: scalar_i32_x_is_const2_eq: 305; CHECK: // %bb.0: 306; CHECK-NEXT: mov w8, #1 307; CHECK-NEXT: mov w9, #43605 308; CHECK-NEXT: lsl w8, w8, w0 309; CHECK-NEXT: movk w9, #43605, lsl #16 310; CHECK-NEXT: tst w8, w9 311; CHECK-NEXT: cset w0, eq 312; CHECK-NEXT: ret 313 %t0 = shl i32 1, %y 314 %t1 = and i32 %t0, 2857740885 315 %res = icmp eq i32 %t1, 0 316 ret i1 %res 317} 318 319define i1 @scalar_i8_bitsinmiddle_slt(i8 %x, i8 %y) nounwind { 320; CHECK-LABEL: scalar_i8_bitsinmiddle_slt: 321; CHECK: // %bb.0: 322; CHECK-NEXT: mov w8, #24 323; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 324; CHECK-NEXT: lsl w8, w8, w1 325; CHECK-NEXT: and w8, w8, w0 326; CHECK-NEXT: ubfx w0, w8, #7, #1 327; CHECK-NEXT: ret 328 %t0 = shl i8 24, %y 329 %t1 = and i8 %t0, %x 330 %res = icmp slt i8 %t1, 0 331 ret i1 %res 332} 333 334define i1 @scalar_i8_signbit_eq_with_nonzero(i8 %x, i8 %y) nounwind { 335; CHECK-LABEL: scalar_i8_signbit_eq_with_nonzero: 336; CHECK: // %bb.0: 337; CHECK-NEXT: mov w8, #-128 338; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 339; CHECK-NEXT: lsl w8, w8, w1 340; CHECK-NEXT: and w8, w8, w0 341; CHECK-NEXT: and w8, w8, #0x80 342; CHECK-NEXT: cmp w8, #1 343; CHECK-NEXT: cset w0, eq 344; CHECK-NEXT: ret 345 %t0 = shl i8 128, %y 346 %t1 = and i8 %t0, %x 347 %res = icmp eq i8 %t1, 1 ; should be comparing with 0 348 ret i1 %res 349} 350