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 & C s>= x 8; Should be transformed into: 9; x s<= C 10; Iff: isPowerOf2(C + 1) 11; C must not be -1, but may be 0. 12 13; ============================================================================ ; 14; Basic positive tests 15; ============================================================================ ; 16 17define i1 @p0(i8 %x) { 18; CHECK-LABEL: @p0( 19; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[X:%.*]], 4 20; CHECK-NEXT: ret i1 [[TMP1]] 21; 22 %tmp0 = and i8 %x, 3 23 %ret = icmp sge i8 %tmp0, %x 24 ret i1 %ret 25} 26 27; ============================================================================ ; 28; Vector tests 29; ============================================================================ ; 30 31define <2 x i1> @p1_vec_splat(<2 x i8> %x) { 32; CHECK-LABEL: @p1_vec_splat( 33; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i8> [[X:%.*]], <i8 4, i8 4> 34; CHECK-NEXT: ret <2 x i1> [[TMP1]] 35; 36 %tmp0 = and <2 x i8> %x, <i8 3, i8 3> 37 %ret = icmp sge <2 x i8> %tmp0, %x 38 ret <2 x i1> %ret 39} 40 41define <2 x i1> @p2_vec_nonsplat(<2 x i8> %x) { 42; CHECK-LABEL: @p2_vec_nonsplat( 43; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i8> [[X:%.*]], <i8 4, i8 16> 44; CHECK-NEXT: ret <2 x i1> [[TMP1]] 45; 46 %tmp0 = and <2 x i8> %x, <i8 3, i8 15> ; doesn't have to be splat. 47 %ret = icmp sge <2 x i8> %tmp0, %x 48 ret <2 x i1> %ret 49} 50 51define <2 x i1> @p2_vec_nonsplat_edgecase(<2 x i8> %x) { 52; CHECK-LABEL: @p2_vec_nonsplat_edgecase( 53; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 0> 54; CHECK-NEXT: [[RET:%.*]] = icmp sge <2 x i8> [[TMP0]], [[X]] 55; CHECK-NEXT: ret <2 x i1> [[RET]] 56; 57 %tmp0 = and <2 x i8> %x, <i8 3, i8 0> 58 %ret = icmp sge <2 x i8> %tmp0, %x 59 ret <2 x i1> %ret 60} 61 62define <3 x i1> @p3_vec_splat_undef(<3 x i8> %x) { 63; CHECK-LABEL: @p3_vec_splat_undef( 64; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <3 x i8> [[X:%.*]], <i8 4, i8 4, i8 4> 65; CHECK-NEXT: ret <3 x i1> [[TMP1]] 66; 67 %tmp0 = and <3 x i8> %x, <i8 3, i8 undef, i8 3> 68 %ret = icmp sge <3 x i8> %tmp0, %x 69 ret <3 x i1> %ret 70} 71 72; ============================================================================ ; 73; One-use tests. We don't care about multi-uses here. 74; ============================================================================ ; 75 76declare void @use8(i8) 77 78define i1 @oneuse0(i8 %x) { 79; CHECK-LABEL: @oneuse0( 80; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X:%.*]], 3 81; CHECK-NEXT: call void @use8(i8 [[TMP0]]) 82; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[X]], 4 83; CHECK-NEXT: ret i1 [[TMP1]] 84; 85 %tmp0 = and i8 %x, 3 86 call void @use8(i8 %tmp0) 87 %ret = icmp sge i8 %tmp0, %x 88 ret i1 %ret 89} 90 91; ============================================================================ ; 92; Negative tests 93; ============================================================================ ; 94 95; Commutativity tests. 96 97declare i8 @gen8() 98 99define i1 @c0() { 100; CHECK-LABEL: @c0( 101; CHECK-NEXT: [[X:%.*]] = call i8 @gen8() 102; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X]], 3 103; CHECK-NEXT: [[RET:%.*]] = icmp sge i8 [[X]], [[TMP0]] 104; CHECK-NEXT: ret i1 [[RET]] 105; 106 %x = call i8 @gen8() 107 %tmp0 = and i8 %x, 3 108 %ret = icmp sge i8 %x, %tmp0 ; swapped order 109 ret i1 %ret 110} 111 112; ============================================================================ ; 113; Rest of negative tests 114; ============================================================================ ; 115 116define i1 @n0(i8 %x) { 117; CHECK-LABEL: @n0( 118; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X:%.*]], 4 119; CHECK-NEXT: [[RET:%.*]] = icmp sge i8 [[TMP0]], [[X]] 120; CHECK-NEXT: ret i1 [[RET]] 121; 122 %tmp0 = and i8 %x, 4 ; power-of-two, but invalid. 123 %ret = icmp sge i8 %tmp0, %x 124 ret i1 %ret 125} 126 127define i1 @n1(i8 %x, i8 %y, i8 %notx) { 128; CHECK-LABEL: @n1( 129; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X:%.*]], 3 130; CHECK-NEXT: [[RET:%.*]] = icmp sge i8 [[TMP0]], [[NOTX:%.*]] 131; CHECK-NEXT: ret i1 [[RET]] 132; 133 %tmp0 = and i8 %x, 3 134 %ret = icmp sge i8 %tmp0, %notx ; not %x 135 ret i1 %ret 136} 137 138define <2 x i1> @n2(<2 x i8> %x) { 139; CHECK-LABEL: @n2( 140; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 16> 141; CHECK-NEXT: [[RET:%.*]] = icmp sge <2 x i8> [[TMP0]], [[X]] 142; CHECK-NEXT: ret <2 x i1> [[RET]] 143; 144 %tmp0 = and <2 x i8> %x, <i8 3, i8 16> ; only the first one is valid. 145 %ret = icmp sge <2 x i8> %tmp0, %x 146 ret <2 x i1> %ret 147} 148 149; ============================================================================ ; 150; Potential miscompiles. 151; ============================================================================ ; 152 153define i1 @nv(i8 %x, i8 %y) { 154; CHECK-LABEL: @nv( 155; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]] 156; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[TMP0]], [[X:%.*]] 157; CHECK-NEXT: [[RET:%.*]] = icmp sge i8 [[TMP1]], [[X]] 158; CHECK-NEXT: ret i1 [[RET]] 159; 160 %tmp0 = lshr i8 -1, %y 161 %tmp1 = and i8 %tmp0, %x 162 %ret = icmp sge i8 %tmp1, %x 163 ret i1 %ret 164} 165 166define <2 x i1> @n3_vec(<2 x i8> %x) { 167; CHECK-LABEL: @n3_vec( 168; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 -1> 169; CHECK-NEXT: [[RET:%.*]] = icmp sge <2 x i8> [[TMP0]], [[X]] 170; CHECK-NEXT: ret <2 x i1> [[RET]] 171; 172 %tmp0 = and <2 x i8> %x, <i8 3, i8 -1> 173 %ret = icmp sge <2 x i8> %tmp0, %x 174 ret <2 x i1> %ret 175} 176 177define <3 x i1> @n4_vec(<3 x i8> %x) { 178; CHECK-LABEL: @n4_vec( 179; CHECK-NEXT: [[TMP0:%.*]] = and <3 x i8> [[X:%.*]], <i8 3, i8 undef, i8 -1> 180; CHECK-NEXT: [[RET:%.*]] = icmp sge <3 x i8> [[TMP0]], [[X]] 181; CHECK-NEXT: ret <3 x i1> [[RET]] 182; 183 %tmp0 = and <3 x i8> %x, <i8 3, i8 undef, i8 -1> 184 %ret = icmp sge <3 x i8> %tmp0, %x 185 ret <3 x i1> %ret 186} 187 188; Commutativity tests with variable 189 190define i1 @cv0(i8 %y) { 191; CHECK-LABEL: @cv0( 192; CHECK-NEXT: [[X:%.*]] = call i8 @gen8() 193; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]] 194; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], [[TMP0]] 195; CHECK-NEXT: [[RET:%.*]] = icmp sge i8 [[TMP1]], [[X]] 196; CHECK-NEXT: ret i1 [[RET]] 197; 198 %x = call i8 @gen8() 199 %tmp0 = lshr i8 -1, %y 200 %tmp1 = and i8 %x, %tmp0 ; swapped order 201 %ret = icmp sge i8 %tmp1, %x 202 ret i1 %ret 203} 204 205define i1 @cv1(i8 %y) { 206; CHECK-LABEL: @cv1( 207; CHECK-NEXT: [[X:%.*]] = call i8 @gen8() 208; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]] 209; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[TMP0]], [[X]] 210; CHECK-NEXT: [[RET:%.*]] = icmp sge i8 [[X]], [[TMP1]] 211; CHECK-NEXT: ret i1 [[RET]] 212; 213 %x = call i8 @gen8() 214 %tmp0 = lshr i8 -1, %y 215 %tmp1 = and i8 %tmp0, %x 216 %ret = icmp sge i8 %x, %tmp1 ; swapped order 217 ret i1 %ret 218} 219 220define i1 @cv2(i8 %y) { 221; CHECK-LABEL: @cv2( 222; CHECK-NEXT: [[X:%.*]] = call i8 @gen8() 223; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]] 224; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], [[TMP0]] 225; CHECK-NEXT: [[RET:%.*]] = icmp sge i8 [[X]], [[TMP1]] 226; CHECK-NEXT: ret i1 [[RET]] 227; 228 %x = call i8 @gen8() 229 %tmp0 = lshr i8 -1, %y 230 %tmp1 = and i8 %x, %tmp0 ; swapped order 231 %ret = icmp sge i8 %x, %tmp1 ; swapped order 232 ret i1 %ret 233} 234