diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -241,6 +241,14 @@ Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); assert(Op0->getType() == Op1->getType()); + // If the shift amount of this shift (but *NOT* funnel shift) is a `sext`, + // we can change it to `zext`. + Value *Y; + if (match(Op1, m_OneUse(m_SExt(m_Value(Y))))) { + return BinaryOperator::Create( + I.getOpcode(), Op0, Builder.CreateZExt(Y, I.getType(), Op1->getName())); + } + // See if we can fold away this shift. if (SimplifyDemandedInstructionBits(I)) return &I; diff --git a/llvm/test/Transforms/InstCombine/load-cmp.ll b/llvm/test/Transforms/InstCombine/load-cmp.ll --- a/llvm/test/Transforms/InstCombine/load-cmp.ll +++ b/llvm/test/Transforms/InstCombine/load-cmp.ll @@ -105,7 +105,7 @@ define i1 @test4_i16(i16 %X) { ; CHECK-LABEL: @test4_i16( -; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[X:%.*]] to i32 +; CHECK-NEXT: [[TMP1:%.*]] = zext i16 [[X:%.*]] to i32 ; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 933, [[TMP1]] ; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], 1 ; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[TMP3]], 0 diff --git a/llvm/test/Transforms/InstCombine/shift-by-signext.ll b/llvm/test/Transforms/InstCombine/shift-by-signext.ll --- a/llvm/test/Transforms/InstCombine/shift-by-signext.ll +++ b/llvm/test/Transforms/InstCombine/shift-by-signext.ll @@ -6,8 +6,8 @@ define i32 @t0_shl(i32 %x, i8 %shamt) { ; CHECK-LABEL: @t0_shl( -; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext i8 [[SHAMT:%.*]] to i32 -; CHECK-NEXT: [[R:%.*]] = shl i32 [[X:%.*]], [[SHAMT_WIDE]] +; CHECK-NEXT: [[SHAMT_WIDE1:%.*]] = zext i8 [[SHAMT:%.*]] to i32 +; CHECK-NEXT: [[R:%.*]] = shl i32 [[X:%.*]], [[SHAMT_WIDE1]] ; CHECK-NEXT: ret i32 [[R]] ; %shamt_wide = sext i8 %shamt to i32 @@ -16,8 +16,8 @@ } define i32 @t1_lshr(i32 %x, i8 %shamt) { ; CHECK-LABEL: @t1_lshr( -; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext i8 [[SHAMT:%.*]] to i32 -; CHECK-NEXT: [[R:%.*]] = lshr i32 [[X:%.*]], [[SHAMT_WIDE]] +; CHECK-NEXT: [[SHAMT_WIDE1:%.*]] = zext i8 [[SHAMT:%.*]] to i32 +; CHECK-NEXT: [[R:%.*]] = lshr i32 [[X:%.*]], [[SHAMT_WIDE1]] ; CHECK-NEXT: ret i32 [[R]] ; %shamt_wide = sext i8 %shamt to i32 @@ -26,8 +26,8 @@ } define i32 @t2_ashr(i32 %x, i8 %shamt) { ; CHECK-LABEL: @t2_ashr( -; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext i8 [[SHAMT:%.*]] to i32 -; CHECK-NEXT: [[R:%.*]] = ashr i32 [[X:%.*]], [[SHAMT_WIDE]] +; CHECK-NEXT: [[SHAMT_WIDE1:%.*]] = zext i8 [[SHAMT:%.*]] to i32 +; CHECK-NEXT: [[R:%.*]] = ashr i32 [[X:%.*]], [[SHAMT_WIDE1]] ; CHECK-NEXT: ret i32 [[R]] ; %shamt_wide = sext i8 %shamt to i32 @@ -37,8 +37,8 @@ define <2 x i32> @t3_vec_shl(<2 x i32> %x, <2 x i8> %shamt) { ; CHECK-LABEL: @t3_vec_shl( -; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext <2 x i8> [[SHAMT:%.*]] to <2 x i32> -; CHECK-NEXT: [[R:%.*]] = shl <2 x i32> [[X:%.*]], [[SHAMT_WIDE]] +; CHECK-NEXT: [[SHAMT_WIDE1:%.*]] = zext <2 x i8> [[SHAMT:%.*]] to <2 x i32> +; CHECK-NEXT: [[R:%.*]] = shl <2 x i32> [[X:%.*]], [[SHAMT_WIDE1]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %shamt_wide = sext <2 x i8> %shamt to <2 x i32> @@ -47,8 +47,8 @@ } define <2 x i32> @t4_vec_lshr(<2 x i32> %x, <2 x i8> %shamt) { ; CHECK-LABEL: @t4_vec_lshr( -; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext <2 x i8> [[SHAMT:%.*]] to <2 x i32> -; CHECK-NEXT: [[R:%.*]] = lshr <2 x i32> [[X:%.*]], [[SHAMT_WIDE]] +; CHECK-NEXT: [[SHAMT_WIDE1:%.*]] = zext <2 x i8> [[SHAMT:%.*]] to <2 x i32> +; CHECK-NEXT: [[R:%.*]] = lshr <2 x i32> [[X:%.*]], [[SHAMT_WIDE1]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %shamt_wide = sext <2 x i8> %shamt to <2 x i32> @@ -57,8 +57,8 @@ } define <2 x i32> @t5_vec_ashr(<2 x i32> %x, <2 x i8> %shamt) { ; CHECK-LABEL: @t5_vec_ashr( -; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext <2 x i8> [[SHAMT:%.*]] to <2 x i32> -; CHECK-NEXT: [[R:%.*]] = ashr <2 x i32> [[X:%.*]], [[SHAMT_WIDE]] +; CHECK-NEXT: [[SHAMT_WIDE1:%.*]] = zext <2 x i8> [[SHAMT:%.*]] to <2 x i32> +; CHECK-NEXT: [[R:%.*]] = ashr <2 x i32> [[X:%.*]], [[SHAMT_WIDE1]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %shamt_wide = sext <2 x i8> %shamt to <2 x i32> @@ -66,33 +66,56 @@ ret <2 x i32> %r } -; This is not valid for funnel shifts -declare i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c) -declare i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c) -define i32 @n6_fshl(i32 %x, i32 %y, i8 %shamt) { +; This is not valid for funnel shifts in general +declare i7 @llvm.fshl.i7(i7 %a, i7 %b, i7 %c) +declare i7 @llvm.fshr.i7(i7 %a, i7 %b, i7 %c) +define i7 @n6_fshl(i7 %x, i7 %y, i6 %shamt) { ; CHECK-LABEL: @n6_fshl( -; CHECK-NEXT: [[SHAMT_WIDE1:%.*]] = zext i8 [[SHAMT:%.*]] to i32 -; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[SHAMT_WIDE1]]) -; CHECK-NEXT: ret i32 [[R]] +; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext i6 [[SHAMT:%.*]] to i7 +; CHECK-NEXT: [[R:%.*]] = call i7 @llvm.fshl.i7(i7 [[X:%.*]], i7 [[Y:%.*]], i7 [[SHAMT_WIDE]]) +; CHECK-NEXT: ret i7 [[R]] ; - %shamt_wide = sext i8 %shamt to i32 - %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %shamt_wide) - ret i32 %r + %shamt_wide = sext i6 %shamt to i7 + %r = call i7 @llvm.fshl.i7(i7 %x, i7 %y, i7 %shamt_wide) + ret i7 %r } -define i32 @n7_fshr(i32 %x, i32 %y, i8 %shamt) { +define i7 @n7_fshr(i7 %x, i7 %y, i6 %shamt) { ; CHECK-LABEL: @n7_fshr( -; CHECK-NEXT: [[SHAMT_WIDE1:%.*]] = zext i8 [[SHAMT:%.*]] to i32 -; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshr.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[SHAMT_WIDE1]]) -; CHECK-NEXT: ret i32 [[R]] +; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext i6 [[SHAMT:%.*]] to i7 +; CHECK-NEXT: [[R:%.*]] = call i7 @llvm.fshr.i7(i7 [[X:%.*]], i7 [[Y:%.*]], i7 [[SHAMT_WIDE]]) +; CHECK-NEXT: ret i7 [[R]] ; - %shamt_wide = sext i8 %shamt to i32 - %r = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %shamt_wide) - ret i32 %r + %shamt_wide = sext i6 %shamt to i7 + %r = call i7 @llvm.fshr.i7(i7 %x, i7 %y, i7 %shamt_wide) + ret i7 %r +} +; And the cases that are safe are handled by SimplifyDemandedBits(). +declare i8 @llvm.fshl.i8(i8 %a, i8 %b, i8 %c) +declare i8 @llvm.fshr.i8(i8 %a, i8 %b, i8 %c) +define i8 @t8_fshl(i8 %x, i8 %y, i6 %shamt) { +; CHECK-LABEL: @t8_fshl( +; CHECK-NEXT: [[SHAMT_WIDE1:%.*]] = zext i6 [[SHAMT:%.*]] to i8 +; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SHAMT_WIDE1]]) +; CHECK-NEXT: ret i8 [[R]] +; + %shamt_wide = sext i6 %shamt to i8 + %r = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %shamt_wide) + ret i8 %r +} +define i8 @t9_fshr(i8 %x, i8 %y, i6 %shamt) { +; CHECK-LABEL: @t9_fshr( +; CHECK-NEXT: [[SHAMT_WIDE1:%.*]] = zext i6 [[SHAMT:%.*]] to i8 +; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SHAMT_WIDE1]]) +; CHECK-NEXT: ret i8 [[R]] +; + %shamt_wide = sext i6 %shamt to i8 + %r = call i8 @llvm.fshr.i8(i8 %x, i8 %y, i8 %shamt_wide) + ret i8 %r } declare void @use32(i32) -define i32 @n8_extrause(i32 %x, i8 %shamt) { -; CHECK-LABEL: @n8_extrause( +define i32 @n10_extrause(i32 %x, i8 %shamt) { +; CHECK-LABEL: @n10_extrause( ; CHECK-NEXT: [[SHAMT_WIDE:%.*]] = sext i8 [[SHAMT:%.*]] to i32 ; CHECK-NEXT: call void @use32(i32 [[SHAMT_WIDE]]) ; CHECK-NEXT: [[R:%.*]] = shl i32 [[X:%.*]], [[SHAMT_WIDE]]