1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -instcombine -S | FileCheck %s 3 4; https://bugs.llvm.org/show_bug.cgi?id=38123 5 6; Pattern: 7; x & ((1 << y) + (-1)) == x 8; Should be transformed into: 9; x u<= ((1 << y) + (-1)) 10; That is then later transformed into: 11; (x >> y) == 0 12 13; This pattern is uncanonical, but we can not canonicalize it due to extra uses. 14 15declare void @use8(i8) 16declare void @use2i8(<2 x i8>) 17declare void @use3i8(<3 x i8>) 18 19; ============================================================================ ; 20; Basic positive tests 21; ============================================================================ ; 22 23define i1 @p0(i8 %x, i8 %y) { 24; CHECK-LABEL: @p0( 25; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Y:%.*]] 26; CHECK-NEXT: call void @use8(i8 [[T0]]) 27; CHECK-NEXT: [[X_HIGHBITS:%.*]] = lshr i8 [[X:%.*]], [[Y]] 28; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X_HIGHBITS]], 0 29; CHECK-NEXT: ret i1 [[TMP1]] 30; 31 %t0 = shl i8 1, %y 32 call void @use8(i8 %t0) 33 %t1 = add i8 %t0, -1 34 %t2 = and i8 %t1, %x 35 %ret = icmp eq i8 %t2, %x 36 ret i1 %ret 37} 38 39; ============================================================================ ; 40; Vector tests 41; ============================================================================ ; 42 43define <2 x i1> @p1_vec(<2 x i8> %x, <2 x i8> %y) { 44; CHECK-LABEL: @p1_vec( 45; CHECK-NEXT: [[T0:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[Y:%.*]] 46; CHECK-NEXT: call void @use2i8(<2 x i8> [[T0]]) 47; CHECK-NEXT: [[X_HIGHBITS:%.*]] = lshr <2 x i8> [[X:%.*]], [[Y]] 48; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i8> [[X_HIGHBITS]], zeroinitializer 49; CHECK-NEXT: ret <2 x i1> [[TMP1]] 50; 51 %t0 = shl <2 x i8> <i8 1, i8 1>, %y 52 call void @use2i8(<2 x i8> %t0) 53 %t1 = add <2 x i8> %t0, <i8 -1, i8 -1> 54 %t2 = and <2 x i8> %t1, %x 55 %ret = icmp eq <2 x i8> %t2, %x 56 ret <2 x i1> %ret 57} 58 59define <3 x i1> @p2_vec_undef0(<3 x i8> %x, <3 x i8> %y) { 60; CHECK-LABEL: @p2_vec_undef0( 61; CHECK-NEXT: [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[Y:%.*]] 62; CHECK-NEXT: call void @use3i8(<3 x i8> [[T0]]) 63; CHECK-NEXT: [[X_HIGHBITS:%.*]] = lshr <3 x i8> [[X:%.*]], [[Y]] 64; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <3 x i8> [[X_HIGHBITS]], zeroinitializer 65; CHECK-NEXT: ret <3 x i1> [[TMP1]] 66; 67 %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %y 68 call void @use3i8(<3 x i8> %t0) 69 %t1 = add <3 x i8> %t0, <i8 -1, i8 -1, i8 -1> 70 %t2 = and <3 x i8> %t1, %x 71 %ret = icmp eq <3 x i8> %t2, %x 72 ret <3 x i1> %ret 73} 74 75define <3 x i1> @p3_vec_undef0(<3 x i8> %x, <3 x i8> %y) { 76; CHECK-LABEL: @p3_vec_undef0( 77; CHECK-NEXT: [[T0:%.*]] = shl <3 x i8> <i8 1, i8 1, i8 1>, [[Y:%.*]] 78; CHECK-NEXT: call void @use3i8(<3 x i8> [[T0]]) 79; CHECK-NEXT: [[X_HIGHBITS:%.*]] = lshr <3 x i8> [[X:%.*]], [[Y]] 80; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <3 x i8> [[X_HIGHBITS]], zeroinitializer 81; CHECK-NEXT: ret <3 x i1> [[TMP1]] 82; 83 %t0 = shl <3 x i8> <i8 1, i8 1, i8 1>, %y 84 call void @use3i8(<3 x i8> %t0) 85 %t1 = add <3 x i8> %t0, <i8 -1, i8 undef, i8 -1> 86 %t2 = and <3 x i8> %t1, %x 87 %ret = icmp eq <3 x i8> %t2, %x 88 ret <3 x i1> %ret 89} 90 91define <3 x i1> @p4_vec_undef2(<3 x i8> %x, <3 x i8> %y) { 92; CHECK-LABEL: @p4_vec_undef2( 93; CHECK-NEXT: [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[Y:%.*]] 94; CHECK-NEXT: call void @use3i8(<3 x i8> [[T0]]) 95; CHECK-NEXT: [[X_HIGHBITS:%.*]] = lshr <3 x i8> [[X:%.*]], [[Y]] 96; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <3 x i8> [[X_HIGHBITS]], zeroinitializer 97; CHECK-NEXT: ret <3 x i1> [[TMP1]] 98; 99 %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %y 100 call void @use3i8(<3 x i8> %t0) 101 %t1 = add <3 x i8> %t0, <i8 -1, i8 undef, i8 -1> 102 %t2 = and <3 x i8> %t1, %x 103 %ret = icmp eq <3 x i8> %t2, %x 104 ret <3 x i1> %ret 105} 106 107; ============================================================================ ; 108; Commutativity tests. 109; ============================================================================ ; 110 111declare i8 @gen8() 112 113define i1 @c0(i8 %y) { 114; CHECK-LABEL: @c0( 115; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Y:%.*]] 116; CHECK-NEXT: call void @use8(i8 [[T0]]) 117; CHECK-NEXT: [[X:%.*]] = call i8 @gen8() 118; CHECK-NEXT: [[X_HIGHBITS:%.*]] = lshr i8 [[X]], [[Y]] 119; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X_HIGHBITS]], 0 120; CHECK-NEXT: ret i1 [[TMP1]] 121; 122 %t0 = shl i8 1, %y 123 call void @use8(i8 %t0) 124 %t1 = add i8 %t0, -1 125 %x = call i8 @gen8() 126 %t2 = and i8 %x, %t1 ; swapped order 127 %ret = icmp eq i8 %t2, %x 128 ret i1 %ret 129} 130 131define i1 @c1(i8 %y) { 132; CHECK-LABEL: @c1( 133; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Y:%.*]] 134; CHECK-NEXT: call void @use8(i8 [[T0]]) 135; CHECK-NEXT: [[X:%.*]] = call i8 @gen8() 136; CHECK-NEXT: [[X_HIGHBITS:%.*]] = lshr i8 [[X]], [[Y]] 137; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X_HIGHBITS]], 0 138; CHECK-NEXT: ret i1 [[TMP1]] 139; 140 %t0 = shl i8 1, %y 141 call void @use8(i8 %t0) 142 %t1 = add i8 %t0, -1 143 %x = call i8 @gen8() 144 %t2 = and i8 %t1, %x 145 %ret = icmp eq i8 %x, %t2 ; swapped order 146 ret i1 %ret 147} 148 149define i1 @c2(i8 %y) { 150; CHECK-LABEL: @c2( 151; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Y:%.*]] 152; CHECK-NEXT: call void @use8(i8 [[T0]]) 153; CHECK-NEXT: [[X:%.*]] = call i8 @gen8() 154; CHECK-NEXT: [[X_HIGHBITS:%.*]] = lshr i8 [[X]], [[Y]] 155; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X_HIGHBITS]], 0 156; CHECK-NEXT: ret i1 [[TMP1]] 157; 158 %t0 = shl i8 1, %y 159 call void @use8(i8 %t0) 160 %t1 = add i8 %t0, -1 161 %x = call i8 @gen8() 162 %t2 = and i8 %x, %t1 ; swapped order 163 %ret = icmp eq i8 %x, %t2 ; swapped order 164 ret i1 %ret 165} 166 167; ============================================================================ ; 168; One-use tests. We don't care about multi-uses here. 169; ============================================================================ ; 170 171define i1 @oneuse0(i8 %x, i8 %y) { 172; CHECK-LABEL: @oneuse0( 173; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Y:%.*]] 174; CHECK-NEXT: call void @use8(i8 [[T0]]) 175; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], -1 176; CHECK-NEXT: call void @use8(i8 [[T1]]) 177; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i8 [[T1]], [[X:%.*]] 178; CHECK-NEXT: ret i1 [[TMP1]] 179; 180 %t0 = shl i8 1, %y 181 call void @use8(i8 %t0) ; needed anyway 182 %t1 = add i8 %t0, -1 183 call void @use8(i8 %t1) 184 %t2 = and i8 %t1, %x 185 %ret = icmp eq i8 %t2, %x 186 ret i1 %ret 187} 188 189define i1 @oneuse1(i8 %x, i8 %y) { 190; CHECK-LABEL: @oneuse1( 191; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Y:%.*]] 192; CHECK-NEXT: call void @use8(i8 [[T0]]) 193; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], -1 194; CHECK-NEXT: [[T2:%.*]] = and i8 [[T1]], [[X:%.*]] 195; CHECK-NEXT: call void @use8(i8 [[T2]]) 196; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i8 [[T1]], [[X]] 197; CHECK-NEXT: ret i1 [[TMP1]] 198; 199 %t0 = shl i8 1, %y 200 call void @use8(i8 %t0) ; needed anyway 201 %t1 = add i8 %t0, -1 202 %t2 = and i8 %t1, %x 203 call void @use8(i8 %t2) 204 %ret = icmp eq i8 %t2, %x 205 ret i1 %ret 206} 207 208define i1 @oneuse2(i8 %x, i8 %y) { 209; CHECK-LABEL: @oneuse2( 210; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Y:%.*]] 211; CHECK-NEXT: call void @use8(i8 [[T0]]) 212; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], -1 213; CHECK-NEXT: call void @use8(i8 [[T1]]) 214; CHECK-NEXT: [[T2:%.*]] = and i8 [[T1]], [[X:%.*]] 215; CHECK-NEXT: call void @use8(i8 [[T2]]) 216; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i8 [[T1]], [[X]] 217; CHECK-NEXT: ret i1 [[TMP1]] 218; 219 %t0 = shl i8 1, %y 220 call void @use8(i8 %t0) 221 %t1 = add i8 %t0, -1 222 call void @use8(i8 %t1) 223 %t2 = and i8 %t1, %x 224 call void @use8(i8 %t2) 225 %ret = icmp eq i8 %t2, %x 226 ret i1 %ret 227} 228 229; ============================================================================ ; 230; Negative tests 231; ============================================================================ ; 232 233define i1 @n0(i8 %x, i8 %y, i8 %notx) { 234; CHECK-LABEL: @n0( 235; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Y:%.*]] 236; CHECK-NEXT: call void @use8(i8 [[T0]]) 237; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], -1 238; CHECK-NEXT: [[T2:%.*]] = and i8 [[T1]], [[X:%.*]] 239; CHECK-NEXT: [[RET:%.*]] = icmp eq i8 [[T2]], [[NOTX:%.*]] 240; CHECK-NEXT: ret i1 [[RET]] 241; 242 %t0 = shl i8 1, %y 243 call void @use8(i8 %t0) 244 %t1 = add i8 %t0, -1 245 %t2 = and i8 %t1, %x 246 %ret = icmp eq i8 %t2, %notx ; not %x 247 ret i1 %ret 248} 249 250define i1 @n1(i8 %x, i8 %y) { 251; CHECK-LABEL: @n1( 252; CHECK-NEXT: [[T0:%.*]] = shl i8 -1, [[Y:%.*]] 253; CHECK-NEXT: call void @use8(i8 [[T0]]) 254; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], -1 255; CHECK-NEXT: [[T2:%.*]] = and i8 [[T1]], [[X:%.*]] 256; CHECK-NEXT: [[RET:%.*]] = icmp eq i8 [[T2]], [[X]] 257; CHECK-NEXT: ret i1 [[RET]] 258; 259 %t0 = shl i8 -1, %y ; not 1 260 call void @use8(i8 %t0) 261 %t1 = add i8 %t0, -1 262 %t2 = and i8 %t1, %x 263 %ret = icmp eq i8 %t2, %x 264 ret i1 %ret 265} 266 267define i1 @n2(i8 %x, i8 %y) { 268; CHECK-LABEL: @n2( 269; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Y:%.*]] 270; CHECK-NEXT: call void @use8(i8 [[T0]]) 271; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], 1 272; CHECK-NEXT: [[T2:%.*]] = and i8 [[T1]], [[X:%.*]] 273; CHECK-NEXT: [[RET:%.*]] = icmp eq i8 [[T2]], [[X]] 274; CHECK-NEXT: ret i1 [[RET]] 275; 276 %t0 = shl i8 1, %y 277 call void @use8(i8 %t0) 278 %t1 = add i8 %t0, 1 ; not -1 279 %t2 = and i8 %t1, %x 280 %ret = icmp eq i8 %t2, %x 281 ret i1 %ret 282} 283