Index: lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- lib/Transforms/InstCombine/InstructionCombining.cpp +++ lib/Transforms/InstCombine/InstructionCombining.cpp @@ -780,8 +780,8 @@ /// Given an instruction with a select as one operand and a constant as the /// other operand, try to fold the binary operator into the select arguments. -/// This also works for Cast instructions, which obviously do not have a second -/// operand. +/// This also works for some Cast instructions, which obviously do not have a +/// second operand. Instruction *InstCombiner::FoldOpIntoSelect(Instruction &Op, SelectInst *SI) { // Don't modify shared select instructions. if (!SI->hasOneUse()) @@ -796,6 +796,20 @@ if (SI->getType()->getScalarType()->isIntegerTy(1)) return nullptr; + // If Op is an extend and this is not a select of constants, do not grow the + // select operand sizes by pulling the extend ahead of the select unless + // there's also a truncate before the select that will allow folding with the + // extend. This is particularly important for vectors because we want to use + // the narrowest operations possible for a given number of vector lanes. + auto isNonTruncVariable = [](Value *V) { + return !isa(V) && !match(V, m_Trunc(m_Value())); + }; + + unsigned SrcWidth = SI->getType()->getScalarSizeInBits(); + unsigned DstWidth = Op.getType()->getScalarSizeInBits(); + if (SrcWidth < DstWidth && (isNonTruncVariable(TV) || isNonTruncVariable(FV))) + return nullptr; + // If it's a bitcast involving vectors, make sure it has the same number of // elements on both sides. if (auto *BC = dyn_cast(&Op)) { Index: test/Transforms/InstCombine/select-bitext.ll =================================================================== --- test/Transforms/InstCombine/select-bitext.ll +++ test/Transforms/InstCombine/select-bitext.ll @@ -5,8 +5,8 @@ define i64 @sel_sext(i32 %a, i1 %cmp) { ; CHECK-LABEL: @sel_sext( -; CHECK-NEXT: [[TMP1:%.*]] = sext i32 %a to i64 -; CHECK-NEXT: [[EXT:%.*]] = select i1 %cmp, i64 [[TMP1]], i64 42 +; CHECK-NEXT: [[SEL:%.*]] = select i1 %cmp, i32 %a, i32 42 +; CHECK-NEXT: [[EXT:%.*]] = sext i32 [[SEL]] to i64 ; CHECK-NEXT: ret i64 [[EXT]] ; %sel = select i1 %cmp, i32 %a, i32 42 @@ -16,8 +16,8 @@ define <4 x i64> @sel_sext_vec(<4 x i32> %a, <4 x i1> %cmp) { ; CHECK-LABEL: @sel_sext_vec( -; CHECK-NEXT: [[TMP1:%.*]] = sext <4 x i32> %a to <4 x i64> -; CHECK-NEXT: [[EXT:%.*]] = select <4 x i1> %cmp, <4 x i64> [[TMP1]], <4 x i64> +; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> %cmp, <4 x i32> %a, <4 x i32> +; CHECK-NEXT: [[EXT:%.*]] = sext <4 x i32> [[SEL]] to <4 x i64> ; CHECK-NEXT: ret <4 x i64> [[EXT]] ; %sel = select <4 x i1> %cmp, <4 x i32> %a, <4 x i32> @@ -27,8 +27,8 @@ define i64 @sel_zext(i32 %a, i1 %cmp) { ; CHECK-LABEL: @sel_zext( -; CHECK-NEXT: [[TMP1:%.*]] = zext i32 %a to i64 -; CHECK-NEXT: [[EXT:%.*]] = select i1 %cmp, i64 [[TMP1]], i64 42 +; CHECK-NEXT: [[SEL:%.*]] = select i1 %cmp, i32 %a, i32 42 +; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[SEL]] to i64 ; CHECK-NEXT: ret i64 [[EXT]] ; %sel = select i1 %cmp, i32 %a, i32 42 @@ -38,8 +38,8 @@ define <4 x i64> @sel_zext_vec(<4 x i32> %a, <4 x i1> %cmp) { ; CHECK-LABEL: @sel_zext_vec( -; CHECK-NEXT: [[TMP1:%.*]] = zext <4 x i32> %a to <4 x i64> -; CHECK-NEXT: [[EXT:%.*]] = select <4 x i1> %cmp, <4 x i64> [[TMP1]], <4 x i64> +; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> %cmp, <4 x i32> %a, <4 x i32> +; CHECK-NEXT: [[EXT:%.*]] = zext <4 x i32> [[SEL]] to <4 x i64> ; CHECK-NEXT: ret <4 x i64> [[EXT]] ; %sel = select <4 x i1> %cmp, <4 x i32> %a, <4 x i32>