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