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=38708 5 6; Pattern: 7; ((1 << bits)+(-1)) u< val 8; Should be transformed into: 9; (val l>> bits) != 0 10 11; NOTE: the innermost shl is not one-use. Else canonicalization happens. 12 13declare void @use8(i8) 14declare void @use2i8(<2 x i8>) 15declare void @use3i8(<3 x i8>) 16 17; ============================================================================ ; 18; Basic positive tests 19; ============================================================================ ; 20 21define i1 @p0(i8 %val, i8 %bits) { 22; CHECK-LABEL: @p0( 23; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS:%.*]] 24; CHECK-NEXT: call void @use8(i8 [[T0]]) 25; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS]] 26; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0 27; CHECK-NEXT: ret i1 [[R]] 28; 29 %t0 = shl i8 1, %bits 30 call void @use8(i8 %t0) 31 %t1 = add i8 %t0, -1 32 %r = icmp ult i8 %t1, %val 33 ret i1 %r 34} 35 36; ============================================================================ ; 37; Vector tests 38; ============================================================================ ; 39 40define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) { 41; CHECK-LABEL: @p1_vec( 42; CHECK-NEXT: [[T0:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[BITS:%.*]] 43; CHECK-NEXT: call void @use2i8(<2 x i8> [[T0]]) 44; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr <2 x i8> [[VAL:%.*]], [[BITS]] 45; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[VAL_HIGHBITS]], zeroinitializer 46; CHECK-NEXT: ret <2 x i1> [[R]] 47; 48 %t0 = shl <2 x i8> <i8 1, i8 1>, %bits 49 call void @use2i8(<2 x i8> %t0) 50 %t1 = add <2 x i8> %t0, <i8 -1, i8 -1> 51 %r = icmp ult <2 x i8> %t1, %val 52 ret <2 x i1> %r 53} 54 55define <3 x i1> @p2_vec_undef0(<3 x i8> %val, <3 x i8> %bits) { 56; CHECK-LABEL: @p2_vec_undef0( 57; CHECK-NEXT: [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]] 58; CHECK-NEXT: call void @use3i8(<3 x i8> [[T0]]) 59; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]] 60; CHECK-NEXT: [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer 61; CHECK-NEXT: ret <3 x i1> [[R]] 62; 63 %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %bits 64 call void @use3i8(<3 x i8> %t0) 65 %t1 = add <3 x i8> %t0, <i8 -1, i8 -1, i8 -1> 66 %r = icmp ult <3 x i8> %t1, %val 67 ret <3 x i1> %r 68} 69 70define <3 x i1> @p2_vec_undef1(<3 x i8> %val, <3 x i8> %bits) { 71; CHECK-LABEL: @p2_vec_undef1( 72; CHECK-NEXT: [[T0:%.*]] = shl <3 x i8> <i8 1, i8 1, i8 1>, [[BITS:%.*]] 73; CHECK-NEXT: call void @use3i8(<3 x i8> [[T0]]) 74; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]] 75; CHECK-NEXT: [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer 76; CHECK-NEXT: ret <3 x i1> [[R]] 77; 78 %t0 = shl <3 x i8> <i8 1, i8 1, i8 1>, %bits 79 call void @use3i8(<3 x i8> %t0) 80 %t1 = add <3 x i8> %t0, <i8 -1, i8 undef, i8 -1> 81 %r = icmp ult <3 x i8> %t1, %val 82 ret <3 x i1> %r 83} 84 85define <3 x i1> @p2_vec_undef2(<3 x i8> %val, <3 x i8> %bits) { 86; CHECK-LABEL: @p2_vec_undef2( 87; CHECK-NEXT: [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]] 88; CHECK-NEXT: call void @use3i8(<3 x i8> [[T0]]) 89; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]] 90; CHECK-NEXT: [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer 91; CHECK-NEXT: ret <3 x i1> [[R]] 92; 93 %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %bits 94 call void @use3i8(<3 x i8> %t0) 95 %t1 = add <3 x i8> %t0, <i8 -1, i8 undef, i8 -1> 96 %r = icmp ult <3 x i8> %t1, %val 97 ret <3 x i1> %r 98} 99 100; ============================================================================ ; 101; Commutativity tests. 102; ============================================================================ ; 103 104declare i8 @gen8() 105 106define i1 @c0(i8 %bits) { 107; CHECK-LABEL: @c0( 108; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS:%.*]] 109; CHECK-NEXT: call void @use8(i8 [[T0]]) 110; CHECK-NEXT: [[VAL:%.*]] = call i8 @gen8() 111; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL]], [[BITS]] 112; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0 113; CHECK-NEXT: ret i1 [[R]] 114; 115 %t0 = shl i8 1, %bits 116 call void @use8(i8 %t0) 117 %t1 = add i8 %t0, -1 118 %val = call i8 @gen8() 119 %r = icmp ugt i8 %val, %t1 ; swapped order and predicate 120 ret i1 %r 121} 122 123; What if we have the same pattern on both sides? 124define i1 @both(i8 %bits0, i8 %bits1) { 125; CHECK-LABEL: @both( 126; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS0:%.*]] 127; CHECK-NEXT: call void @use8(i8 [[T0]]) 128; CHECK-NEXT: [[T2:%.*]] = shl i8 1, [[BITS1:%.*]] 129; CHECK-NEXT: call void @use8(i8 [[T2]]) 130; CHECK-NEXT: [[T3:%.*]] = add i8 [[T2]], -1 131; CHECK-NEXT: [[T3_HIGHBITS:%.*]] = lshr i8 [[T3]], [[BITS0]] 132; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[T3_HIGHBITS]], 0 133; CHECK-NEXT: ret i1 [[R]] 134; 135 %t0 = shl i8 1, %bits0 136 call void @use8(i8 %t0) 137 %t1 = add i8 %t0, -1 138 %t2 = shl i8 1, %bits1 139 call void @use8(i8 %t2) 140 %t3 = add i8 %t2, -1 141 %r = icmp ult i8 %t1, %t3 142 ret i1 %r 143} 144 145; ============================================================================ ; 146; One-use tests. 147; ============================================================================ ; 148 149define i1 @oneuse(i8 %val, i8 %bits) { 150; CHECK-LABEL: @oneuse( 151; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS:%.*]] 152; CHECK-NEXT: call void @use8(i8 [[T0]]) 153; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], -1 154; CHECK-NEXT: call void @use8(i8 [[T1]]) 155; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]] 156; CHECK-NEXT: ret i1 [[R]] 157; 158 %t0 = shl i8 1, %bits 159 call void @use8(i8 %t0) ; this is needed anyway 160 %t1 = add i8 %t0, -1 161 call void @use8(i8 %t1) 162 %r = icmp ult i8 %t1, %val 163 ret i1 %r 164} 165 166; ============================================================================ ; 167; Negative tests 168; ============================================================================ ; 169 170define i1 @n0(i8 %val, i8 %bits) { 171; CHECK-LABEL: @n0( 172; CHECK-NEXT: [[T0:%.*]] = shl i8 -1, [[BITS:%.*]] 173; CHECK-NEXT: call void @use8(i8 [[T0]]) 174; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], -1 175; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]] 176; CHECK-NEXT: ret i1 [[R]] 177; 178 %t0 = shl i8 -1, %bits ; constant is not 1 179 call void @use8(i8 %t0) 180 %t1 = add i8 %t0, -1 181 %r = icmp ult i8 %t1, %val 182 ret i1 %r 183} 184 185define i1 @n1(i8 %val, i8 %bits) { 186; CHECK-LABEL: @n1( 187; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS:%.*]] 188; CHECK-NEXT: call void @use8(i8 [[T0]]) 189; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], 1 190; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]] 191; CHECK-NEXT: ret i1 [[R]] 192; 193 %t0 = shl i8 1, %bits 194 call void @use8(i8 %t0) 195 %t1 = add i8 %t0, 1 ; constant is not -1 196 %r = icmp ult i8 %t1, %val 197 ret i1 %r 198} 199 200define <2 x i1> @n2_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) { 201; CHECK-LABEL: @n2_vec_nonsplat( 202; CHECK-NEXT: [[T0:%.*]] = shl <2 x i8> <i8 1, i8 -1>, [[BITS:%.*]] 203; CHECK-NEXT: call void @use2i8(<2 x i8> [[T0]]) 204; CHECK-NEXT: [[T1:%.*]] = add <2 x i8> [[T0]], <i8 -1, i8 -1> 205; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i8> [[T1]], [[VAL:%.*]] 206; CHECK-NEXT: ret <2 x i1> [[R]] 207; 208 %t0 = shl <2 x i8> <i8 1, i8 -1>, %bits ; again, wrong constant 209 call void @use2i8(<2 x i8> %t0) 210 %t1 = add <2 x i8> %t0, <i8 -1, i8 -1> 211 %r = icmp ult <2 x i8> %t1, %val 212 ret <2 x i1> %r 213} 214 215define <2 x i1> @n3_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) { 216; CHECK-LABEL: @n3_vec_nonsplat( 217; CHECK-NEXT: [[T0:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[BITS:%.*]] 218; CHECK-NEXT: call void @use2i8(<2 x i8> [[T0]]) 219; CHECK-NEXT: [[T1:%.*]] = add <2 x i8> [[T0]], <i8 -1, i8 1> 220; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i8> [[T1]], [[VAL:%.*]] 221; CHECK-NEXT: ret <2 x i1> [[R]] 222; 223 %t0 = shl <2 x i8> <i8 1, i8 1>, %bits 224 call void @use2i8(<2 x i8> %t0) 225 %t1 = add <2 x i8> %t0, <i8 -1, i8 1> ; again, wrong constant 226 %r = icmp ult <2 x i8> %t1, %val 227 ret <2 x i1> %r 228} 229 230define i1 @n3(i8 %val, i8 %bits) { 231; CHECK-LABEL: @n3( 232; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS:%.*]] 233; CHECK-NEXT: call void @use8(i8 [[T0]]) 234; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], -1 235; CHECK-NEXT: [[R:%.*]] = icmp ule i8 [[T1]], [[VAL:%.*]] 236; CHECK-NEXT: ret i1 [[R]] 237; 238 %t0 = shl i8 1, %bits 239 call void @use8(i8 %t0) 240 %t1 = add i8 %t0, -1 241 %r = icmp ule i8 %t1, %val ; wrong predicate 242 ret i1 %r 243} 244 245define i1 @n4(i8 %bits) { 246; CHECK-LABEL: @n4( 247; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS:%.*]] 248; CHECK-NEXT: call void @use8(i8 [[T0]]) 249; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0]], -1 250; CHECK-NEXT: [[VAL:%.*]] = call i8 @gen8() 251; CHECK-NEXT: [[R:%.*]] = icmp uge i8 [[VAL]], [[T1]] 252; CHECK-NEXT: ret i1 [[R]] 253; 254 %t0 = shl i8 1, %bits 255 call void @use8(i8 %t0) 256 %t1 = add i8 %t0, -1 257 %val = call i8 @gen8() 258 %r = icmp uge i8 %val, %t1 ; swapped order and [wrong] predicate 259 ret i1 %r 260} 261