200 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=instcombine -S | FileCheck %s3 4; If we have some pattern that leaves only some low bits set, and then performs5; left-shift of those bits, we can combine those two shifts into a shift+mask.6 7; There are many variants to this pattern:8; a) (trunc (x & ((1 << maskNbits) - 1))) << shiftNbits9; simplify to:10; (trunc(x)) << shiftNbits11 12; Simple tests.13 14declare void @use32(i32)15declare void @use64(i64)16 17define i32 @t0_basic(i64 %x, i32 %nbits) {18; CHECK-LABEL: @t0_basic(19; CHECK-NEXT: [[T0:%.*]] = zext i32 [[NBITS:%.*]] to i6420; CHECK-NEXT: [[T1:%.*]] = shl nuw i64 1, [[T0]]21; CHECK-NEXT: [[T2:%.*]] = add i64 [[T1]], -122; CHECK-NEXT: [[T3:%.*]] = sub i32 32, [[NBITS]]23; CHECK-NEXT: [[T4:%.*]] = and i64 [[T2]], [[X:%.*]]24; CHECK-NEXT: call void @use32(i32 [[NBITS]])25; CHECK-NEXT: call void @use64(i64 [[T0]])26; CHECK-NEXT: call void @use64(i64 [[T1]])27; CHECK-NEXT: call void @use64(i64 [[T2]])28; CHECK-NEXT: call void @use32(i32 [[T3]])29; CHECK-NEXT: call void @use64(i64 [[T4]])30; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[X]] to i3231; CHECK-NEXT: [[T6:%.*]] = shl i32 [[TMP1]], [[T3]]32; CHECK-NEXT: ret i32 [[T6]]33;34 %t0 = zext i32 %nbits to i6435 %t1 = shl i64 1, %t036 %t2 = add i64 %t1, -137 %t3 = sub i32 32, %nbits38 %t4 = and i64 %t2, %x39 40 call void @use32(i32 %nbits)41 call void @use64(i64 %t0)42 call void @use64(i64 %t1)43 call void @use64(i64 %t2)44 call void @use32(i32 %t3)45 call void @use64(i64 %t4)46 47 %t5 = trunc i64 %t4 to i3248 %t6 = shl i32 %t5, %t349 ret i32 %t650}51 52; Vectors53 54declare void @use8xi32(<8 x i32>)55declare void @use8xi64(<8 x i64>)56 57define <8 x i32> @t1_vec_splat(<8 x i64> %x, <8 x i32> %nbits) {58; CHECK-LABEL: @t1_vec_splat(59; CHECK-NEXT: [[T0:%.*]] = zext <8 x i32> [[NBITS:%.*]] to <8 x i64>60; CHECK-NEXT: [[T1:%.*]] = shl nuw <8 x i64> splat (i64 1), [[T0]]61; CHECK-NEXT: [[T2:%.*]] = add <8 x i64> [[T1]], splat (i64 -1)62; CHECK-NEXT: [[T3:%.*]] = sub <8 x i32> splat (i32 32), [[NBITS]]63; CHECK-NEXT: [[T4:%.*]] = and <8 x i64> [[T2]], [[X:%.*]]64; CHECK-NEXT: call void @use8xi32(<8 x i32> [[NBITS]])65; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T0]])66; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T1]])67; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T2]])68; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T3]])69; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T4]])70; CHECK-NEXT: [[TMP1:%.*]] = trunc <8 x i64> [[X]] to <8 x i32>71; CHECK-NEXT: [[T6:%.*]] = shl <8 x i32> [[TMP1]], [[T3]]72; CHECK-NEXT: ret <8 x i32> [[T6]]73;74 %t0 = zext <8 x i32> %nbits to <8 x i64>75 %t1 = shl <8 x i64> <i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1>, %t076 %t2 = add <8 x i64> %t1, <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1>77 %t3 = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32>, %nbits78 %t4 = and <8 x i64> %t2, %x79 80 call void @use8xi32(<8 x i32> %nbits)81 call void @use8xi64(<8 x i64> %t0)82 call void @use8xi64(<8 x i64> %t1)83 call void @use8xi64(<8 x i64> %t2)84 call void @use8xi32(<8 x i32> %t3)85 call void @use8xi64(<8 x i64> %t4)86 87 %t5 = trunc <8 x i64> %t4 to <8 x i32>88 %t6 = shl <8 x i32> %t5, %t389 ret <8 x i32> %t690}91 92define <8 x i32> @t2_vec_splat_poison(<8 x i64> %x, <8 x i32> %nbits) {93; CHECK-LABEL: @t2_vec_splat_poison(94; CHECK-NEXT: [[T0:%.*]] = zext <8 x i32> [[NBITS:%.*]] to <8 x i64>95; CHECK-NEXT: [[T1:%.*]] = shl nuw <8 x i64> <i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 poison, i64 1>, [[T0]]96; CHECK-NEXT: [[T2:%.*]] = add <8 x i64> [[T1]], <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 poison, i64 -1>97; CHECK-NEXT: [[T3:%.*]] = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 poison, i32 32>, [[NBITS]]98; CHECK-NEXT: [[T4:%.*]] = and <8 x i64> [[T2]], [[X:%.*]]99; CHECK-NEXT: call void @use8xi32(<8 x i32> [[NBITS]])100; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T0]])101; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T1]])102; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T2]])103; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T3]])104; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T4]])105; CHECK-NEXT: [[TMP1:%.*]] = trunc <8 x i64> [[X]] to <8 x i32>106; CHECK-NEXT: [[T6:%.*]] = shl <8 x i32> [[TMP1]], [[T3]]107; CHECK-NEXT: ret <8 x i32> [[T6]]108;109 %t0 = zext <8 x i32> %nbits to <8 x i64>110 %t1 = shl <8 x i64> <i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 poison, i64 1>, %t0111 %t2 = add <8 x i64> %t1, <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 poison, i64 -1>112 %t3 = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 poison, i32 32>, %nbits113 %t4 = and <8 x i64> %t2, %x114 115 call void @use8xi32(<8 x i32> %nbits)116 call void @use8xi64(<8 x i64> %t0)117 call void @use8xi64(<8 x i64> %t1)118 call void @use8xi64(<8 x i64> %t2)119 call void @use8xi32(<8 x i32> %t3)120 call void @use8xi64(<8 x i64> %t4)121 122 %t5 = trunc <8 x i64> %t4 to <8 x i32>123 %t6 = shl <8 x i32> %t5, %t3124 ret <8 x i32> %t6125}126 127define <8 x i32> @t3_vec_nonsplat(<8 x i64> %x, <8 x i32> %nbits) {128; CHECK-LABEL: @t3_vec_nonsplat(129; CHECK-NEXT: [[T0:%.*]] = zext <8 x i32> [[NBITS:%.*]] to <8 x i64>130; CHECK-NEXT: [[T1:%.*]] = shl nuw <8 x i64> splat (i64 1), [[T0]]131; CHECK-NEXT: [[T2:%.*]] = add <8 x i64> [[T1]], splat (i64 -1)132; CHECK-NEXT: [[T3:%.*]] = sub <8 x i32> splat (i32 32), [[NBITS]]133; CHECK-NEXT: [[T4:%.*]] = and <8 x i64> [[T2]], [[X:%.*]]134; CHECK-NEXT: call void @use8xi32(<8 x i32> [[NBITS]])135; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T0]])136; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T1]])137; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T2]])138; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T3]])139; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T4]])140; CHECK-NEXT: [[TMP1:%.*]] = trunc <8 x i64> [[X]] to <8 x i32>141; CHECK-NEXT: [[T6:%.*]] = shl <8 x i32> [[TMP1]], [[T3]]142; CHECK-NEXT: ret <8 x i32> [[T6]]143;144 %t0 = zext <8 x i32> %nbits to <8 x i64>145 %t1 = shl <8 x i64> <i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1>, %t0146 %t2 = add <8 x i64> %t1, <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1>147 %t3 = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32>, %nbits148 %t4 = and <8 x i64> %t2, %x149 150 call void @use8xi32(<8 x i32> %nbits)151 call void @use8xi64(<8 x i64> %t0)152 call void @use8xi64(<8 x i64> %t1)153 call void @use8xi64(<8 x i64> %t2)154 call void @use8xi32(<8 x i32> %t3)155 call void @use8xi64(<8 x i64> %t4)156 157 %t5 = trunc <8 x i64> %t4 to <8 x i32>158 %t6 = shl <8 x i32> %t5, %t3159 ret <8 x i32> %t6160}161 162; Extra uses163 164define i32 @n4_extrause(i64 %x, i32 %nbits) {165; CHECK-LABEL: @n4_extrause(166; CHECK-NEXT: [[T0:%.*]] = zext i32 [[NBITS:%.*]] to i64167; CHECK-NEXT: [[T1:%.*]] = shl nuw i64 1, [[T0]]168; CHECK-NEXT: [[T2:%.*]] = add i64 [[T1]], -1169; CHECK-NEXT: [[T3:%.*]] = sub i32 32, [[NBITS]]170; CHECK-NEXT: [[T4:%.*]] = and i64 [[T2]], [[X:%.*]]171; CHECK-NEXT: call void @use32(i32 [[NBITS]])172; CHECK-NEXT: call void @use64(i64 [[T0]])173; CHECK-NEXT: call void @use64(i64 [[T1]])174; CHECK-NEXT: call void @use64(i64 [[T2]])175; CHECK-NEXT: call void @use32(i32 [[T3]])176; CHECK-NEXT: call void @use64(i64 [[T4]])177; CHECK-NEXT: [[T5:%.*]] = trunc i64 [[T4]] to i32178; CHECK-NEXT: call void @use32(i32 [[T5]])179; CHECK-NEXT: [[T6:%.*]] = shl i32 [[T5]], [[T3]]180; CHECK-NEXT: ret i32 [[T6]]181;182 %t0 = zext i32 %nbits to i64183 %t1 = shl i64 1, %t0184 %t2 = add i64 %t1, -1185 %t3 = sub i32 32, %nbits186 %t4 = and i64 %t2, %x187 188 call void @use32(i32 %nbits)189 call void @use64(i64 %t0)190 call void @use64(i64 %t1)191 call void @use64(i64 %t2)192 call void @use32(i32 %t3)193 call void @use64(i64 %t4)194 195 %t5 = trunc i64 %t4 to i32196 call void @use32(i32 %t5)197 %t6 = shl i32 %t5, %t3198 ret i32 %t6199}200