Index: lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCasts.cpp +++ lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -480,6 +480,38 @@ return nullptr; } +/// Try to narrow the width of an insert element. This could be generalized for +/// any vector constant, but we limit the transform to insertion into undef to +/// avoid potential backend problems from unsupported insertion widths. This +/// could also be extended to handle the case of inserting a scalar constant +/// into a vector variable. +static Instruction *shrinkInsertElt(CastInst &Trunc, + InstCombiner::BuilderTy &Builder) { + Instruction::CastOps Opcode = Trunc.getOpcode(); + assert((Opcode == Instruction::Trunc || Opcode == Instruction::FPTrunc) && + "Unexpected instruction for shrinking"); + + auto *InsElt = dyn_cast(Trunc.getOperand(0)); + if (!InsElt || !InsElt->hasOneUse()) + return nullptr; + + Type *DestTy = Trunc.getType(); + Type *DestScalarTy = DestTy->getScalarType(); + Value *VecOp = InsElt->getOperand(0); + Value *ScalarOp = InsElt->getOperand(1); + Value *Index = InsElt->getOperand(2); + + if (isa(VecOp)) { + // trunc (inselt undef, X, Index) --> inselt undef, (trunc X), Index + // fptrunc (inselt undef, X, Index) --> inselt undef, (fptrunc X), Index + UndefValue *NarrowUndef = UndefValue::get(DestTy); + Value *NarrowOp = Builder.CreateCast(Opcode, ScalarOp, DestScalarTy); + return InsertElementInst::Create(NarrowUndef, NarrowOp, Index); + } + + return nullptr; +} + Instruction *InstCombiner::visitTrunc(TruncInst &CI) { if (Instruction *Result = commonCastTransforms(CI)) return Result; @@ -574,6 +606,9 @@ if (Instruction *I = shrinkSplatShuffle(CI, *Builder)) return I; + if (Instruction *I = shrinkInsertElt(CI, *Builder)) + return I; + if (Src->hasOneUse() && isa(SrcTy) && shouldChangeType(SrcTy, DestTy)) { // Transform "trunc (shl X, cst)" -> "shl (trunc X), cst" so long as the @@ -1426,6 +1461,9 @@ } } + if (Instruction *I = shrinkInsertElt(CI, *Builder)) + return I; + return nullptr; } Index: test/Transforms/InstCombine/vector-casts.ll =================================================================== --- test/Transforms/InstCombine/vector-casts.ll +++ test/Transforms/InstCombine/vector-casts.ll @@ -216,6 +216,35 @@ ret <8 x i32> %wrong } +; Hoist a trunc to a scalar if we're inserting into an undef vector. +; trunc (inselt undef, X, Index) --> inselt undef, (trunc X), Index + +define <3 x i16> @trunc_inselt_undef(i32 %x) { +; CHECK-LABEL: @trunc_inselt_undef( +; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %x to i16 +; CHECK-NEXT: [[TRUNC:%.*]] = insertelement <3 x i16> undef, i16 [[TMP1]], i32 1 +; CHECK-NEXT: ret <3 x i16> [[TRUNC]] +; + %vec = insertelement <3 x i32> undef, i32 %x, i32 1 + %trunc = trunc <3 x i32> %vec to <3 x i16> + ret <3 x i16> %trunc +} + +; Hoist a trunc to a scalar if we're inserting into an undef vector. +; trunc (inselt undef, X, Index) --> inselt undef, (trunc X), Index + +define <2 x float> @fptrunc_inselt_undef(double %x, i32 %index) { +; CHECK-LABEL: @fptrunc_inselt_undef( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc double %x to float +; CHECK-NEXT: [[TRUNC:%.*]] = insertelement <2 x float> undef, float [[TMP1]], i32 %index +; CHECK-NEXT: ret <2 x float> [[TRUNC]] +; + %vec = insertelement <2 x double> , double %x, i32 %index + %trunc = fptrunc <2 x double> %vec to <2 x float> + ret <2 x float> %trunc +} + +; TODO: Strengthen the backend, so we can have this canonicalization. ; Insert a scalar int into a constant vector and truncate: ; trunc (inselt C, X, Index) --> inselt C, (trunc X), Index @@ -230,6 +259,7 @@ ret <3 x i16> %trunc } +; TODO: Strengthen the backend, so we can have this canonicalization. ; Insert a scalar FP into a constant vector and FP truncate: ; fptrunc (inselt C, X, Index) --> inselt C, (fptrunc X), Index @@ -244,6 +274,7 @@ ret <2 x float> %trunc } +; TODO: Strengthen the backend, so we can have this canonicalization. ; Insert a scalar int constant into a vector and truncate: ; trunc (inselt X, C, Index) --> inselt (trunc X), C', Index @@ -258,6 +289,7 @@ ret <8 x i16> %trunc } +; TODO: Strengthen the backend, so we can have this canonicalization. ; Insert a scalar FP constant into a vector and FP truncate: ; fptrunc (inselt X, C, Index) --> inselt (fptrunc X), C', Index