1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instcombine -S | FileCheck %s 3 4declare void @use6(i6) 5declare void @use8(i8) 6 7define i6 @trunc_lshr(i8 %x) { 8; CHECK-LABEL: @trunc_lshr( 9; CHECK-NEXT: [[TMP1:%.*]] = trunc i8 [[X:%.*]] to i6 10; CHECK-NEXT: [[TMP2:%.*]] = lshr i6 [[TMP1]], 2 11; CHECK-NEXT: [[R:%.*]] = and i6 [[TMP2]], 14 12; CHECK-NEXT: ret i6 [[R]] 13; 14 %s = lshr i8 %x, 2 15 %t = trunc i8 %s to i6 16 %r = and i6 %t, 14 17 ret i6 %r 18} 19 20; The 'and' is eliminated. 21 22define i6 @trunc_lshr_exact_mask(i8 %x) { 23; CHECK-LABEL: @trunc_lshr_exact_mask( 24; CHECK-NEXT: [[TMP1:%.*]] = trunc i8 [[X:%.*]] to i6 25; CHECK-NEXT: [[TMP2:%.*]] = lshr i6 [[TMP1]], 2 26; CHECK-NEXT: ret i6 [[TMP2]] 27; 28 %s = lshr i8 %x, 2 29 %t = trunc i8 %s to i6 30 %r = and i6 %t, 15 31 ret i6 %r 32} 33 34; negative test - a high bit of x is in the result 35 36define i6 @trunc_lshr_big_mask(i8 %x) { 37; CHECK-LABEL: @trunc_lshr_big_mask( 38; CHECK-NEXT: [[S:%.*]] = lshr i8 [[X:%.*]], 2 39; CHECK-NEXT: [[T:%.*]] = trunc nuw i8 [[S]] to i6 40; CHECK-NEXT: [[R:%.*]] = and i6 [[T]], 31 41; CHECK-NEXT: ret i6 [[R]] 42; 43 %s = lshr i8 %x, 2 44 %t = trunc i8 %s to i6 45 %r = and i6 %t, 31 46 ret i6 %r 47} 48 49; negative test - too many uses 50 51define i6 @trunc_lshr_use1(i8 %x) { 52; CHECK-LABEL: @trunc_lshr_use1( 53; CHECK-NEXT: [[S:%.*]] = lshr i8 [[X:%.*]], 2 54; CHECK-NEXT: call void @use8(i8 [[S]]) 55; CHECK-NEXT: [[T:%.*]] = trunc nuw i8 [[S]] to i6 56; CHECK-NEXT: [[R:%.*]] = and i6 [[T]], 15 57; CHECK-NEXT: ret i6 [[R]] 58; 59 %s = lshr i8 %x, 2 60 call void @use8(i8 %s) 61 %t = trunc i8 %s to i6 62 %r = and i6 %t, 15 63 ret i6 %r 64} 65 66; negative test - too many uses 67 68define i6 @trunc_lshr_use2(i8 %x) { 69; CHECK-LABEL: @trunc_lshr_use2( 70; CHECK-NEXT: [[S:%.*]] = lshr i8 [[X:%.*]], 2 71; CHECK-NEXT: [[T:%.*]] = trunc nuw i8 [[S]] to i6 72; CHECK-NEXT: call void @use6(i6 [[T]]) 73; CHECK-NEXT: [[R:%.*]] = and i6 [[T]], 15 74; CHECK-NEXT: ret i6 [[R]] 75; 76 %s = lshr i8 %x, 2 77 %t = trunc i8 %s to i6 78 call void @use6(i6 %t) 79 %r = and i6 %t, 15 80 ret i6 %r 81} 82 83; Splat vectors are ok. 84 85define <2 x i7> @trunc_lshr_vec_splat(<2 x i16> %x) { 86; CHECK-LABEL: @trunc_lshr_vec_splat( 87; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i16> [[X:%.*]] to <2 x i7> 88; CHECK-NEXT: [[TMP2:%.*]] = lshr <2 x i7> [[TMP1]], splat (i7 5) 89; CHECK-NEXT: [[R:%.*]] = and <2 x i7> [[TMP2]], splat (i7 1) 90; CHECK-NEXT: ret <2 x i7> [[R]] 91; 92 %s = lshr <2 x i16> %x, <i16 5, i16 5> 93 %t = trunc <2 x i16> %s to <2 x i7> 94 %r = and <2 x i7> %t, <i7 1, i7 1> 95 ret <2 x i7> %r 96} 97 98; The 'and' is eliminated. 99 100define <2 x i7> @trunc_lshr_vec_splat_exact_mask(<2 x i16> %x) { 101; CHECK-LABEL: @trunc_lshr_vec_splat_exact_mask( 102; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i16> [[X:%.*]] to <2 x i7> 103; CHECK-NEXT: [[TMP2:%.*]] = lshr <2 x i7> [[TMP1]], splat (i7 6) 104; CHECK-NEXT: ret <2 x i7> [[TMP2]] 105; 106 %s = lshr <2 x i16> %x, <i16 6, i16 6> 107 %t = trunc <2 x i16> %s to <2 x i7> 108 %r = and <2 x i7> %t, <i7 1, i7 1> 109 ret <2 x i7> %r 110} 111 112; negative test - the shift is too big for the narrow type 113 114define <2 x i7> @trunc_lshr_big_shift(<2 x i16> %x) { 115; CHECK-LABEL: @trunc_lshr_big_shift( 116; CHECK-NEXT: [[S:%.*]] = lshr <2 x i16> [[X:%.*]], splat (i16 7) 117; CHECK-NEXT: [[T:%.*]] = trunc <2 x i16> [[S]] to <2 x i7> 118; CHECK-NEXT: [[R:%.*]] = and <2 x i7> [[T]], splat (i7 1) 119; CHECK-NEXT: ret <2 x i7> [[R]] 120; 121 %s = lshr <2 x i16> %x, <i16 7, i16 7> 122 %t = trunc <2 x i16> %s to <2 x i7> 123 %r = and <2 x i7> %t, <i7 1, i7 1> 124 ret <2 x i7> %r 125} 126 127; High bits could also be set rather than cleared. 128 129define i6 @or_trunc_lshr(i8 %x) { 130; CHECK-LABEL: @or_trunc_lshr( 131; CHECK-NEXT: [[TMP1:%.*]] = trunc i8 [[X:%.*]] to i6 132; CHECK-NEXT: [[TMP2:%.*]] = lshr i6 [[TMP1]], 1 133; CHECK-NEXT: [[R:%.*]] = or disjoint i6 [[TMP2]], -32 134; CHECK-NEXT: ret i6 [[R]] 135; 136 %s = lshr i8 %x, 1 137 %t = trunc i8 %s to i6 138 %r = or i6 %t, 32 ; 0b100000 139 ret i6 %r 140} 141 142define i6 @or_trunc_lshr_more(i8 %x) { 143; CHECK-LABEL: @or_trunc_lshr_more( 144; CHECK-NEXT: [[TMP1:%.*]] = trunc i8 [[X:%.*]] to i6 145; CHECK-NEXT: [[TMP2:%.*]] = lshr i6 [[TMP1]], 4 146; CHECK-NEXT: [[R:%.*]] = or disjoint i6 [[TMP2]], -4 147; CHECK-NEXT: ret i6 [[R]] 148; 149 %s = lshr i8 %x, 4 150 %t = trunc i8 %s to i6 151 %r = or i6 %t, 60 ; 0b111100 152 ret i6 %r 153} 154 155; negative test - need all high bits to be undemanded 156 157define i6 @or_trunc_lshr_small_mask(i8 %x) { 158; CHECK-LABEL: @or_trunc_lshr_small_mask( 159; CHECK-NEXT: [[S:%.*]] = lshr i8 [[X:%.*]], 4 160; CHECK-NEXT: [[T:%.*]] = trunc nuw nsw i8 [[S]] to i6 161; CHECK-NEXT: [[R:%.*]] = or i6 [[T]], -8 162; CHECK-NEXT: ret i6 [[R]] 163; 164 %s = lshr i8 %x, 4 165 %t = trunc i8 %s to i6 166 %r = or i6 %t, 56 ; 0b111000 167 ret i6 %r 168} 169