1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=aggressive-instcombine -S | FileCheck %s 3 4define i16 @shl_1(i8 %x) { 5; CHECK-LABEL: @shl_1( 6; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i16 7; CHECK-NEXT: [[SHL:%.*]] = shl i16 [[ZEXT]], 1 8; CHECK-NEXT: ret i16 [[SHL]] 9; 10 %zext = zext i8 %x to i32 11 %shl = shl i32 %zext, 1 12 %trunc = trunc i32 %shl to i16 13 ret i16 %trunc 14} 15 16define i16 @shl_15(i8 %x) { 17; CHECK-LABEL: @shl_15( 18; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i16 19; CHECK-NEXT: [[SHL:%.*]] = shl i16 [[ZEXT]], 15 20; CHECK-NEXT: ret i16 [[SHL]] 21; 22 %zext = zext i8 %x to i32 23 %shl = shl i32 %zext, 15 24 %trunc = trunc i32 %shl to i16 25 ret i16 %trunc 26} 27 28; Negative test - shift amount isn't less than target bitwidth 29 30define i16 @shl_16(i8 %x) { 31; CHECK-LABEL: @shl_16( 32; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32 33; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[ZEXT]], 16 34; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[SHL]] to i16 35; CHECK-NEXT: ret i16 [[TRUNC]] 36; 37 %zext = zext i8 %x to i32 38 %shl = shl i32 %zext, 16 39 %trunc = trunc i32 %shl to i16 40 ret i16 %trunc 41} 42 43; Negative test -- variable shift amount 44 45define i16 @shl_var_shift_amount(i8 %x, i8 %y) { 46; CHECK-LABEL: @shl_var_shift_amount( 47; CHECK-NEXT: [[ZEXT_X:%.*]] = zext i8 [[X:%.*]] to i32 48; CHECK-NEXT: [[ZEXT_Y:%.*]] = zext i8 [[Y:%.*]] to i32 49; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[ZEXT_X]], [[ZEXT_Y]] 50; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[SHL]] to i16 51; CHECK-NEXT: ret i16 [[TRUNC]] 52; 53 %zext.x = zext i8 %x to i32 54 %zext.y = zext i8 %y to i32 55 %shl = shl i32 %zext.x, %zext.y 56 %trunc = trunc i32 %shl to i16 57 ret i16 %trunc 58} 59 60define i16 @shl_var_bounded_shift_amount(i8 %x, i8 %y) { 61; CHECK-LABEL: @shl_var_bounded_shift_amount( 62; CHECK-NEXT: [[ZEXT_X:%.*]] = zext i8 [[X:%.*]] to i16 63; CHECK-NEXT: [[ZEXT_Y:%.*]] = zext i8 [[Y:%.*]] to i16 64; CHECK-NEXT: [[AND:%.*]] = and i16 [[ZEXT_Y]], 15 65; CHECK-NEXT: [[SHL:%.*]] = shl i16 [[ZEXT_X]], [[AND]] 66; CHECK-NEXT: ret i16 [[SHL]] 67; 68 %zext.x = zext i8 %x to i32 69 %zext.y = zext i8 %y to i32 70 %and = and i32 %zext.y, 15 71 %shl = shl i32 %zext.x, %and 72 %trunc = trunc i32 %shl to i16 73 ret i16 %trunc 74} 75 76; Negative test (https://reviews.llvm.org/D108091#2950930) 77 78define i32 @shl_check_no_overflow(i32 %x, i16 %amt) { 79; CHECK-LABEL: @shl_check_no_overflow( 80; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[X:%.*]] to i64 81; CHECK-NEXT: [[SEXT:%.*]] = sext i16 [[AMT:%.*]] to i64 82; CHECK-NEXT: [[AND:%.*]] = and i64 [[SEXT]], 4294967295 83; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[ZEXT]], [[AND]] 84; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[SHL]] to i32 85; CHECK-NEXT: ret i32 [[TRUNC]] 86; 87 %zext = zext i32 %x to i64 88 %sext = sext i16 %amt to i64 89 %and = and i64 %sext, 4294967295 90 %shl = shl i64 %zext, %and 91 %trunc = trunc i64 %shl to i32 92 ret i32 %trunc 93} 94 95define <2 x i16> @shl_vector(<2 x i8> %x) { 96; CHECK-LABEL: @shl_vector( 97; CHECK-NEXT: [[Z:%.*]] = zext <2 x i8> [[X:%.*]] to <2 x i16> 98; CHECK-NEXT: [[S:%.*]] = shl <2 x i16> [[Z]], <i16 4, i16 10> 99; CHECK-NEXT: ret <2 x i16> [[S]] 100; 101 %z = zext <2 x i8> %x to <2 x i32> 102 %s = shl <2 x i32> %z, <i32 4, i32 10> 103 %t = trunc <2 x i32> %s to <2 x i16> 104 ret <2 x i16> %t 105} 106 107; Negative test - can only fold to <2 x i16>, requiring new vector type 108 109define <2 x i8> @shl_vector_no_new_vector_type(<2 x i8> %x) { 110; CHECK-LABEL: @shl_vector_no_new_vector_type( 111; CHECK-NEXT: [[Z:%.*]] = zext <2 x i8> [[X:%.*]] to <2 x i32> 112; CHECK-NEXT: [[S:%.*]] = shl <2 x i32> [[Z]], <i32 4, i32 10> 113; CHECK-NEXT: [[T:%.*]] = trunc <2 x i32> [[S]] to <2 x i8> 114; CHECK-NEXT: ret <2 x i8> [[T]] 115; 116 %z = zext <2 x i8> %x to <2 x i32> 117 %s = shl <2 x i32> %z, <i32 4, i32 10> 118 %t = trunc <2 x i32> %s to <2 x i8> 119 ret <2 x i8> %t 120} 121 122; Negative test 123 124define <2 x i16> @shl_vector_large_shift_amount(<2 x i8> %x) { 125; CHECK-LABEL: @shl_vector_large_shift_amount( 126; CHECK-NEXT: [[Z:%.*]] = zext <2 x i8> [[X:%.*]] to <2 x i32> 127; CHECK-NEXT: [[S:%.*]] = shl <2 x i32> [[Z]], <i32 16, i32 5> 128; CHECK-NEXT: [[T:%.*]] = trunc <2 x i32> [[S]] to <2 x i16> 129; CHECK-NEXT: ret <2 x i16> [[T]] 130; 131 %z = zext <2 x i8> %x to <2 x i32> 132 %s = shl <2 x i32> %z, <i32 16, i32 5> 133 %t = trunc <2 x i32> %s to <2 x i16> 134 ret <2 x i16> %t 135} 136 137define i16 @shl_nuw(i8 %x) { 138; CHECK-LABEL: @shl_nuw( 139; CHECK-NEXT: [[Z:%.*]] = zext i8 [[X:%.*]] to i16 140; CHECK-NEXT: [[S:%.*]] = shl i16 [[Z]], 15 141; CHECK-NEXT: ret i16 [[S]] 142; 143 %z = zext i8 %x to i32 144 %s = shl nuw i32 %z, 15 145 %t = trunc i32 %s to i16 146 ret i16 %t 147} 148 149define i16 @shl_nsw(i8 %x) { 150; CHECK-LABEL: @shl_nsw( 151; CHECK-NEXT: [[Z:%.*]] = zext i8 [[X:%.*]] to i16 152; CHECK-NEXT: [[S:%.*]] = shl i16 [[Z]], 15 153; CHECK-NEXT: ret i16 [[S]] 154; 155 %z = zext i8 %x to i32 156 %s = shl nsw i32 %z, 15 157 %t = trunc i32 %s to i16 158 ret i16 %t 159} 160