250 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:5; (data & (-1 << nbits)) outer>> nbits6; Or7; ((data inner>> nbits) << nbits) outer>> nbits8; The mask is redundant, and can be dropped:9; data outer>> nbits10; This is valid for both lshr and ashr in both positions and any combination.11; We must *not* preserve 'exact' on that final right-shift.12 13define i32 @t0_lshr(i32 %data, i32 %nbits) {14; CHECK-LABEL: @t0_lshr(15; CHECK-NEXT: [[T0:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]16; CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]17; CHECK-NEXT: [[T2:%.*]] = lshr exact i32 [[T1]], [[NBITS]]18; CHECK-NEXT: ret i32 [[T2]]19;20 %t0 = shl i32 -1, %nbits21 %t1 = and i32 %t0, %data22 %t2 = lshr exact i32 %t1, %nbits ; while there, test that we *don't* propagate 'exact'23 ret i32 %t224}25define i32 @t1_sshr(i32 %data, i32 %nbits) {26; CHECK-LABEL: @t1_sshr(27; CHECK-NEXT: [[T0:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]28; CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]29; CHECK-NEXT: [[T2:%.*]] = ashr exact i32 [[T1]], [[NBITS]]30; CHECK-NEXT: ret i32 [[T2]]31;32 %t0 = shl i32 -1, %nbits33 %t1 = and i32 %t0, %data34 %t2 = ashr exact i32 %t1, %nbits ; while there, test that we *don't* propagate 'exact'35 ret i32 %t236}37 38; Vectors39 40define <4 x i32> @t2_vec(<4 x i32> %data, <4 x i32> %nbits) {41; CHECK-LABEL: @t2_vec(42; CHECK-NEXT: [[T0:%.*]] = shl nsw <4 x i32> splat (i32 -1), [[NBITS:%.*]]43; CHECK-NEXT: [[T1:%.*]] = and <4 x i32> [[T0]], [[DATA:%.*]]44; CHECK-NEXT: [[T2:%.*]] = lshr <4 x i32> [[T1]], [[NBITS]]45; CHECK-NEXT: ret <4 x i32> [[T2]]46;47 %t0 = shl <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %nbits48 %t1 = and <4 x i32> %t0, %data49 %t2 = lshr <4 x i32> %t1, %nbits50 ret <4 x i32> %t251}52 53define <4 x i32> @t3_vec_undef(<4 x i32> %data, <4 x i32> %nbits) {54; CHECK-LABEL: @t3_vec_undef(55; CHECK-NEXT: [[T0:%.*]] = shl <4 x i32> <i32 -1, i32 -1, i32 undef, i32 -1>, [[NBITS:%.*]]56; CHECK-NEXT: [[T1:%.*]] = and <4 x i32> [[T0]], [[DATA:%.*]]57; CHECK-NEXT: [[T2:%.*]] = lshr <4 x i32> [[T1]], [[NBITS]]58; CHECK-NEXT: ret <4 x i32> [[T2]]59;60 %t0 = shl <4 x i32> <i32 -1, i32 -1, i32 undef, i32 -1>, %nbits61 %t1 = and <4 x i32> %t0, %data62 %t2 = lshr <4 x i32> %t1, %nbits63 ret <4 x i32> %t264}65 66; Extra uses67 68declare void @use32(i32)69 70define i32 @t4_extrause0(i32 %data, i32 %nbits) {71; CHECK-LABEL: @t4_extrause0(72; CHECK-NEXT: [[T0:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]73; CHECK-NEXT: call void @use32(i32 [[T0]])74; CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]75; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]76; CHECK-NEXT: ret i32 [[T2]]77;78 %t0 = shl i32 -1, %nbits79 call void @use32(i32 %t0)80 %t1 = and i32 %t0, %data81 %t2 = lshr i32 %t1, %nbits82 ret i32 %t283}84 85define i32 @t5_extrause1(i32 %data, i32 %nbits) {86; CHECK-LABEL: @t5_extrause1(87; CHECK-NEXT: [[T0:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]88; CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]89; CHECK-NEXT: call void @use32(i32 [[T1]])90; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]91; CHECK-NEXT: ret i32 [[T2]]92;93 %t0 = shl i32 -1, %nbits94 %t1 = and i32 %t0, %data95 call void @use32(i32 %t1)96 %t2 = lshr i32 %t1, %nbits97 ret i32 %t298}99 100define i32 @t6_extrause2(i32 %data, i32 %nbits) {101; CHECK-LABEL: @t6_extrause2(102; CHECK-NEXT: [[T0:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]103; CHECK-NEXT: call void @use32(i32 [[T0]])104; CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]105; CHECK-NEXT: call void @use32(i32 [[T1]])106; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]107; CHECK-NEXT: ret i32 [[T2]]108;109 %t0 = shl i32 -1, %nbits110 call void @use32(i32 %t0)111 %t1 = and i32 %t0, %data112 call void @use32(i32 %t1)113 %t2 = lshr i32 %t1, %nbits114 ret i32 %t2115}116 117; Non-canonical mask pattern. Let's just test a single case with all-extra uses.118 119define i32 @t7_noncanonical_lshr_lshr_extrauses(i32 %data, i32 %nbits) {120; CHECK-LABEL: @t7_noncanonical_lshr_lshr_extrauses(121; CHECK-NEXT: [[T0:%.*]] = lshr i32 [[DATA:%.*]], [[NBITS:%.*]]122; CHECK-NEXT: call void @use32(i32 [[T0]])123; CHECK-NEXT: [[T1:%.*]] = shl i32 [[T0]], [[NBITS]]124; CHECK-NEXT: call void @use32(i32 [[T1]])125; CHECK-NEXT: [[T2:%.*]] = lshr exact i32 [[T1]], [[NBITS]]126; CHECK-NEXT: ret i32 [[T2]]127;128 %t0 = lshr i32 %data, %nbits129 call void @use32(i32 %t0)130 %t1 = shl i32 %t0, %nbits131 call void @use32(i32 %t1)132 %t2 = lshr i32 %t1, %nbits133 ret i32 %t2134}135 136define i32 @t8_noncanonical_lshr_ashr_extrauses(i32 %data, i32 %nbits) {137; CHECK-LABEL: @t8_noncanonical_lshr_ashr_extrauses(138; CHECK-NEXT: [[T0:%.*]] = lshr i32 [[DATA:%.*]], [[NBITS:%.*]]139; CHECK-NEXT: call void @use32(i32 [[T0]])140; CHECK-NEXT: [[T1:%.*]] = shl i32 [[T0]], [[NBITS]]141; CHECK-NEXT: call void @use32(i32 [[T1]])142; CHECK-NEXT: [[T2:%.*]] = ashr exact i32 [[T1]], [[NBITS]]143; CHECK-NEXT: ret i32 [[T2]]144;145 %t0 = lshr i32 %data, %nbits146 call void @use32(i32 %t0)147 %t1 = shl i32 %t0, %nbits148 call void @use32(i32 %t1)149 %t2 = ashr i32 %t1, %nbits150 ret i32 %t2151}152 153define i32 @t9_noncanonical_ashr_lshr_extrauses(i32 %data, i32 %nbits) {154; CHECK-LABEL: @t9_noncanonical_ashr_lshr_extrauses(155; CHECK-NEXT: [[T0:%.*]] = ashr i32 [[DATA:%.*]], [[NBITS:%.*]]156; CHECK-NEXT: call void @use32(i32 [[T0]])157; CHECK-NEXT: [[T1:%.*]] = shl i32 [[T0]], [[NBITS]]158; CHECK-NEXT: call void @use32(i32 [[T1]])159; CHECK-NEXT: [[T2:%.*]] = lshr exact i32 [[T1]], [[NBITS]]160; CHECK-NEXT: ret i32 [[T2]]161;162 %t0 = ashr i32 %data, %nbits163 call void @use32(i32 %t0)164 %t1 = shl i32 %t0, %nbits165 call void @use32(i32 %t1)166 %t2 = lshr i32 %t1, %nbits167 ret i32 %t2168}169 170define i32 @t10_noncanonical_ashr_ashr_extrauses(i32 %data, i32 %nbits) {171; CHECK-LABEL: @t10_noncanonical_ashr_ashr_extrauses(172; CHECK-NEXT: [[T0:%.*]] = ashr i32 [[DATA:%.*]], [[NBITS:%.*]]173; CHECK-NEXT: call void @use32(i32 [[T0]])174; CHECK-NEXT: [[T1:%.*]] = shl i32 [[T0]], [[NBITS]]175; CHECK-NEXT: call void @use32(i32 [[T1]])176; CHECK-NEXT: [[T2:%.*]] = ashr exact i32 [[T1]], [[NBITS]]177; CHECK-NEXT: ret i32 [[T2]]178;179 %t0 = ashr i32 %data, %nbits180 call void @use32(i32 %t0)181 %t1 = shl i32 %t0, %nbits182 call void @use32(i32 %t1)183 %t2 = ashr i32 %t1, %nbits184 ret i32 %t2185}186 187; Commutativity188 189declare i32 @gen32()190 191define i32 @t11_commutative(i32 %nbits) {192; CHECK-LABEL: @t11_commutative(193; CHECK-NEXT: [[DATA:%.*]] = call i32 @gen32()194; CHECK-NEXT: [[T0:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]195; CHECK-NEXT: [[T1:%.*]] = and i32 [[DATA]], [[T0]]196; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]197; CHECK-NEXT: ret i32 [[T2]]198;199 %data = call i32 @gen32()200 %t0 = shl i32 -1, %nbits201 %t1 = and i32 %data, %t0 ; swapped202 %t2 = lshr i32 %t1, %nbits203 ret i32 %t2204}205 206; Negative tests207 208define i32 @n12(i32 %data, i32 %nbits) {209; CHECK-LABEL: @n12(210; CHECK-NEXT: [[T0:%.*]] = shl i32 2147483647, [[NBITS:%.*]]211; CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]212; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]213; CHECK-NEXT: ret i32 [[T2]]214;215 %t0 = shl i32 2147483647, %nbits ; must be shifting -1216 %t1 = and i32 %t0, %data217 %t2 = lshr i32 %t1, %nbits218 ret i32 %t2219}220 221define i32 @n13(i32 %data, i32 %nbits0, i32 %nbits1) {222; CHECK-LABEL: @n13(223; CHECK-NEXT: [[T0:%.*]] = shl nsw i32 -1, [[NBITS0:%.*]]224; CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]225; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[T1]], [[NBITS1:%.*]]226; CHECK-NEXT: ret i32 [[T2]]227;228 %t0 = shl i32 -1, %nbits0229 %t1 = and i32 %t0, %data230 %t2 = lshr i32 %t1, %nbits1 ; different shift amounts231 ret i32 %t2232}233 234define i32 @n14(i32 %data, i32 %nbits0, i32 %nbits1, i32 %nbits2) {235; CHECK-LABEL: @n14(236; CHECK-NEXT: [[T0:%.*]] = lshr i32 [[DATA:%.*]], [[NBITS0:%.*]]237; CHECK-NEXT: call void @use32(i32 [[T0]])238; CHECK-NEXT: [[T1:%.*]] = shl i32 [[T0]], [[NBITS1:%.*]]239; CHECK-NEXT: call void @use32(i32 [[T1]])240; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[T1]], [[NBITS2:%.*]]241; CHECK-NEXT: ret i32 [[T2]]242;243 %t0 = lshr i32 %data, %nbits0244 call void @use32(i32 %t0)245 %t1 = shl i32 %t0, %nbits1 ; different shift amounts246 call void @use32(i32 %t1)247 %t2 = lshr i32 %t1, %nbits2 ; different shift amounts248 ret i32 %t2249}250