diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -559,6 +559,14 @@ return UndefValue::get(I->getType()); } } else { + // This is a variable shift, so we can't shift the demand mask by a known + // amount. But if we are not demanding high bits, then we are not + // demanding those bits from the pre-shifted operand either. + if (unsigned CTLZ = DemandedMask.countLeadingZeros()) { + APInt DemandedFromOp(APInt::getLowBitsSet(BitWidth, BitWidth - CTLZ)); + if (SimplifyDemandedBits(I, 0, DemandedFromOp, Known, Depth + 1)) + return I; + } computeKnownBits(I, Known, Depth, CxtI); } break; diff --git a/llvm/test/Transforms/InstCombine/rotate.ll b/llvm/test/Transforms/InstCombine/rotate.ll --- a/llvm/test/Transforms/InstCombine/rotate.ll +++ b/llvm/test/Transforms/InstCombine/rotate.ll @@ -443,7 +443,8 @@ ; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[SHIFT:%.*]] to i8 ; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], 3 ; CHECK-NEXT: [[TMP3:%.*]] = trunc i32 [[V:%.*]] to i8 -; CHECK-NEXT: [[CONV2:%.*]] = call i8 @llvm.fshr.i8(i8 [[TMP3]], i8 [[TMP3]], i8 [[TMP2]]) +; CHECK-NEXT: [[TMP4:%.*]] = trunc i32 [[V]] to i8 +; CHECK-NEXT: [[CONV2:%.*]] = call i8 @llvm.fshr.i8(i8 [[TMP3]], i8 [[TMP4]], i8 [[TMP2]]) ; CHECK-NEXT: ret i8 [[CONV2]] ; %and = and i32 %shift, 3 diff --git a/llvm/test/Transforms/InstCombine/shl-demand.ll b/llvm/test/Transforms/InstCombine/shl-demand.ll --- a/llvm/test/Transforms/InstCombine/shl-demand.ll +++ b/llvm/test/Transforms/InstCombine/shl-demand.ll @@ -3,8 +3,8 @@ define i16 @sext_shl_trunc_same_size(i16 %x, i32 %y) { ; CHECK-LABEL: @sext_shl_trunc_same_size( -; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[X:%.*]] to i32 -; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CONV]], [[Y:%.*]] +; CHECK-NEXT: [[CONV1:%.*]] = zext i16 [[X:%.*]] to i32 +; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CONV1]], [[Y:%.*]] ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[SHL]] to i16 ; CHECK-NEXT: ret i16 [[T]] ; @@ -16,8 +16,8 @@ define i5 @sext_shl_trunc_smaller(i16 %x, i32 %y) { ; CHECK-LABEL: @sext_shl_trunc_smaller( -; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[X:%.*]] to i32 -; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CONV]], [[Y:%.*]] +; CHECK-NEXT: [[CONV1:%.*]] = zext i16 [[X:%.*]] to i32 +; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CONV1]], [[Y:%.*]] ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[SHL]] to i5 ; CHECK-NEXT: ret i5 [[T]] ; @@ -27,6 +27,8 @@ ret i5 %t } +; negative test - demanding 1 high-bit too many to change the extend + define i17 @sext_shl_trunc_larger(i16 %x, i32 %y) { ; CHECK-LABEL: @sext_shl_trunc_larger( ; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[X:%.*]] to i32 @@ -42,8 +44,8 @@ define i32 @sext_shl_mask(i16 %x, i32 %y) { ; CHECK-LABEL: @sext_shl_mask( -; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[X:%.*]] to i32 -; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CONV]], [[Y:%.*]] +; CHECK-NEXT: [[CONV1:%.*]] = zext i16 [[X:%.*]] to i32 +; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CONV1]], [[Y:%.*]] ; CHECK-NEXT: [[T:%.*]] = and i32 [[SHL]], 65535 ; CHECK-NEXT: ret i32 [[T]] ; @@ -53,6 +55,8 @@ ret i32 %t } +; negative test - demanding a bit that could change with sext + define i32 @sext_shl_mask_higher(i16 %x, i32 %y) { ; CHECK-LABEL: @sext_shl_mask_higher( ; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[X:%.*]] to i32 @@ -66,9 +70,11 @@ ret i32 %t } +; May need some, but not all of the bits set by the 'or'. + define i32 @set_shl_mask(i32 %x, i32 %y) { ; CHECK-LABEL: @set_shl_mask( -; CHECK-NEXT: [[Z:%.*]] = or i32 [[X:%.*]], 196609 +; CHECK-NEXT: [[Z:%.*]] = or i32 [[X:%.*]], 65537 ; CHECK-NEXT: [[S:%.*]] = shl i32 [[Z]], [[Y:%.*]] ; CHECK-NEXT: [[R:%.*]] = and i32 [[S]], 65536 ; CHECK-NEXT: ret i32 [[R]]