1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instcombine -S | FileCheck %s 3 4; PR51305: prefer `-(x & 1)` over `(x << (bitwidth(x)-1)) a>> (bitwidth(x)-1)` 5; as the pattern to splat the lowest bit. 6 7declare void @use8(i8) 8 9; Basic positive scalar tests 10define i8 @t0(i8 %x) { 11; CHECK-LABEL: @t0( 12; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], 1 13; CHECK-NEXT: [[R:%.*]] = sub nsw i8 0, [[TMP1]] 14; CHECK-NEXT: ret i8 [[R]] 15; 16 %i0 = shl i8 %x, 7 17 %r = ashr i8 %i0, 7 18 ret i8 %r 19} 20define i16 @t1_otherbitwidth(i16 %x) { 21; CHECK-LABEL: @t1_otherbitwidth( 22; CHECK-NEXT: [[TMP1:%.*]] = and i16 [[X:%.*]], 1 23; CHECK-NEXT: [[R:%.*]] = sub nsw i16 0, [[TMP1]] 24; CHECK-NEXT: ret i16 [[R]] 25; 26 %i0 = shl i16 %x, 15 27 %r = ashr i16 %i0, 15 28 ret i16 %r 29} 30 31; Basic positive vector tests 32define <2 x i8> @t2_vec(<2 x i8> %x) { 33; CHECK-LABEL: @t2_vec( 34; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], splat (i8 1) 35; CHECK-NEXT: [[R:%.*]] = sub nsw <2 x i8> zeroinitializer, [[TMP1]] 36; CHECK-NEXT: ret <2 x i8> [[R]] 37; 38 %i0 = shl <2 x i8> %x, <i8 7, i8 7> 39 %r = ashr <2 x i8> %i0, <i8 7, i8 7> 40 ret <2 x i8> %r 41} 42 43; TODO: The result constants should contain poison instead of undef. 44 45define <3 x i8> @t3_vec_poison0(<3 x i8> %x) { 46; CHECK-LABEL: @t3_vec_poison0( 47; CHECK-NEXT: [[TMP1:%.*]] = and <3 x i8> [[X:%.*]], <i8 1, i8 undef, i8 1> 48; CHECK-NEXT: [[R:%.*]] = sub <3 x i8> zeroinitializer, [[TMP1]] 49; CHECK-NEXT: ret <3 x i8> [[R]] 50; 51 %i0 = shl <3 x i8> %x, <i8 7, i8 poison, i8 7> 52 %r = ashr <3 x i8> %i0, <i8 7, i8 7, i8 7> 53 ret <3 x i8> %r 54} 55define <3 x i8> @t4_vec_poison1(<3 x i8> %x) { 56; CHECK-LABEL: @t4_vec_poison1( 57; CHECK-NEXT: [[TMP1:%.*]] = and <3 x i8> [[X:%.*]], <i8 1, i8 undef, i8 1> 58; CHECK-NEXT: [[R:%.*]] = sub <3 x i8> zeroinitializer, [[TMP1]] 59; CHECK-NEXT: ret <3 x i8> [[R]] 60; 61 %i0 = shl <3 x i8> %x, <i8 7, i8 7, i8 7> 62 %r = ashr <3 x i8> %i0, <i8 7, i8 poison, i8 7> 63 ret <3 x i8> %r 64} 65define <3 x i8> @t5_vec_poison2(<3 x i8> %x) { 66; CHECK-LABEL: @t5_vec_poison2( 67; CHECK-NEXT: [[TMP1:%.*]] = and <3 x i8> [[X:%.*]], <i8 1, i8 undef, i8 1> 68; CHECK-NEXT: [[R:%.*]] = sub <3 x i8> zeroinitializer, [[TMP1]] 69; CHECK-NEXT: ret <3 x i8> [[R]] 70; 71 %i0 = shl <3 x i8> %x, <i8 7, i8 poison, i8 7> 72 %r = ashr <3 x i8> %i0, <i8 7, i8 poison, i8 7> 73 ret <3 x i8> %r 74} 75 76; In general, the `shl` needs to go away. 77define i8 @n6_extrause(i8 %x) { 78; CHECK-LABEL: @n6_extrause( 79; CHECK-NEXT: [[I0:%.*]] = shl i8 [[X:%.*]], 7 80; CHECK-NEXT: call void @use8(i8 [[I0]]) 81; CHECK-NEXT: [[R:%.*]] = ashr exact i8 [[I0]], 7 82; CHECK-NEXT: ret i8 [[R]] 83; 84 %i0 = shl i8 %x, 7 85 call void @use8(i8 %i0) 86 %r = ashr i8 %i0, 7 87 ret i8 %r 88} 89 90; But, if the input to the shift is already masked, then we're fine. 91define i8 @t7_already_masked(i8 %x) { 92; CHECK-LABEL: @t7_already_masked( 93; CHECK-NEXT: [[I0:%.*]] = and i8 [[X:%.*]], 1 94; CHECK-NEXT: call void @use8(i8 [[I0]]) 95; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], 1 96; CHECK-NEXT: [[R:%.*]] = sub nsw i8 0, [[TMP1]] 97; CHECK-NEXT: ret i8 [[R]] 98; 99 %i0 = and i8 %x, 1 100 call void @use8(i8 %i0) 101 %i1 = shl i8 %i0, 7 102 %r = ashr i8 %i1, 7 103 ret i8 %r 104} 105; FIXME: we should fold this 106define i8 @t8_already_masked_extrause(i8 %x) { 107; CHECK-LABEL: @t8_already_masked_extrause( 108; CHECK-NEXT: [[I0:%.*]] = and i8 [[X:%.*]], 1 109; CHECK-NEXT: call void @use8(i8 [[I0]]) 110; CHECK-NEXT: [[I1:%.*]] = shl i8 [[X]], 7 111; CHECK-NEXT: call void @use8(i8 [[I1]]) 112; CHECK-NEXT: [[R:%.*]] = ashr exact i8 [[I1]], 7 113; CHECK-NEXT: ret i8 [[R]] 114; 115 %i0 = and i8 %x, 1 116 call void @use8(i8 %i0) 117 %i1 = shl i8 %i0, 7 118 call void @use8(i8 %i1) 119 %r = ashr i8 %i1, 7 120 ret i8 %r 121} 122define i8 @n9_wrongly_masked_extrause(i8 %x) { 123; CHECK-LABEL: @n9_wrongly_masked_extrause( 124; CHECK-NEXT: [[I0:%.*]] = and i8 [[X:%.*]], 3 125; CHECK-NEXT: call void @use8(i8 [[I0]]) 126; CHECK-NEXT: [[I1:%.*]] = shl i8 [[X]], 7 127; CHECK-NEXT: call void @use8(i8 [[I1]]) 128; CHECK-NEXT: [[R:%.*]] = ashr exact i8 [[I1]], 7 129; CHECK-NEXT: ret i8 [[R]] 130; 131 %i0 = and i8 %x, 3 132 call void @use8(i8 %i0) 133 %i1 = shl i8 %i0, 7 134 call void @use8(i8 %i1) 135 %r = ashr i8 %i1, 7 136 ret i8 %r 137} 138 139; Wrong shift amounts 140define i8 @n10(i8 %x) { 141; CHECK-LABEL: @n10( 142; CHECK-NEXT: [[I0:%.*]] = shl i8 [[X:%.*]], 6 143; CHECK-NEXT: [[R:%.*]] = ashr i8 [[I0]], 7 144; CHECK-NEXT: ret i8 [[R]] 145; 146 %i0 = shl i8 %x, 6 ; not 7 147 %r = ashr i8 %i0, 7 148 ret i8 %r 149} 150define i8 @n11(i8 %x) { 151; CHECK-LABEL: @n11( 152; CHECK-NEXT: [[I0:%.*]] = shl i8 [[X:%.*]], 7 153; CHECK-NEXT: [[R:%.*]] = ashr exact i8 [[I0]], 6 154; CHECK-NEXT: ret i8 [[R]] 155; 156 %i0 = shl i8 %x, 7 157 %r = ashr i8 %i0, 6 ; not 7 158 ret i8 %r 159} 160define i8 @n12(i8 %x) { 161; CHECK-LABEL: @n12( 162; CHECK-NEXT: [[I0:%.*]] = shl i8 [[X:%.*]], 6 163; CHECK-NEXT: [[R:%.*]] = ashr exact i8 [[I0]], 6 164; CHECK-NEXT: ret i8 [[R]] 165; 166 %i0 = shl i8 %x, 6 ; not 7 167 %r = ashr i8 %i0, 6 ; not 7 168 ret i8 %r 169} 170