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<InsertElementInst>(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<UndefValue>(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;
if (Instruction *I = shrinkSplatShuffle(CI, *Builder))
return I;
+ if (Instruction *I = shrinkInsertElt(CI, *Builder))
+ return I;
+
if (Src->hasOneUse() && isa<IntegerType>(SrcTy) &&
shouldChangeType(SrcTy, DestTy)) {
// Transform "trunc (shl X, cst)" -> "shl (trunc X), cst" so long as the
}
}
+ if (Instruction *I = shrinkInsertElt(CI, *Builder))
+ return I;
+
return nullptr;
}
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 undef, double undef>, 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
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
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
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