From 055889cfb9bb8732591acf81ed6ae84ddf808a5c Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 15 Apr 2006 01:39:45 +0000 Subject: [PATCH] significant cleanups to code that uses insert/extractelt heavily. This builds maximal shuffles out of them where possible. llvm-svn: 27717 --- .../Scalar/InstructionCombining.cpp | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index f9b01c7a30d..a502bd25fef 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -137,6 +137,7 @@ namespace { Instruction *visitStoreInst(StoreInst &SI); Instruction *visitBranchInst(BranchInst &BI); Instruction *visitSwitchInst(SwitchInst &SI); + Instruction *visitInsertElementInst(InsertElementInst &IE); Instruction *visitExtractElementInst(ExtractElementInst &EI); Instruction *visitShuffleVectorInst(ShuffleVectorInst &SVI); @@ -6915,6 +6916,126 @@ Instruction *InstCombiner::visitExtractElementInst(ExtractElementInst &EI) { return 0; } +/// CollectShuffleElements - We are building a shuffle between V and RHSVec, +/// which are both packed values with identical types. Return a shuffle mask +/// that computes V. +static Value *CollectShuffleElements(Value *V, std::vector &Mask, + Value *RHSVec) { + assert(isa(V->getType()) && V->getType() == RHSVec->getType() && + "Invalid shuffle!"); + unsigned NumElts = cast(V->getType())->getNumElements(); + + if (isa(V)) { + Mask.assign(NumElts, UndefValue::get(Type::UIntTy)); + return V; + } else if (isa(V)) { + Mask.assign(NumElts, ConstantUInt::get(Type::UIntTy, 0)); + return V; + } else if (InsertElementInst *IEI = dyn_cast(V)) { + // If this is an insert of an extract from some other vector, include it. + Value *VecOp = IEI->getOperand(0); + Value *ScalarOp = IEI->getOperand(1); + Value *IdxOp = IEI->getOperand(2); + + if (ExtractElementInst *EI = dyn_cast(ScalarOp)) { + if (isa(EI->getOperand(1)) && isa(IdxOp) && + EI->getOperand(0)->getType() == V->getType()) { + unsigned ExtractedIdx = + cast(EI->getOperand(1))->getRawValue(); + unsigned InsertedIdx = cast(IdxOp)->getRawValue(); + + // Either the extracted from or inserted into vector must be RHSVec, + // otherwise we'd end up with a shuffle of three inputs. + if (EI->getOperand(0) == RHSVec) { + Value *V = CollectShuffleElements(VecOp, Mask, RHSVec); + Mask[InsertedIdx & (NumElts-1)] = + ConstantUInt::get(Type::UIntTy, NumElts+ExtractedIdx); + return V; + } + + if (VecOp == RHSVec) { + Value *V = CollectShuffleElements(EI->getOperand(0), Mask, RHSVec); + // Everything but the extracted element is replaced with the RHS. + for (unsigned i = 0; i != NumElts; ++i) { + if (i != InsertedIdx) + Mask[i] = ConstantUInt::get(Type::UIntTy, NumElts+i); + } + return V; + } + } + } + } + + + // Otherwise, can't do anything fancy. Return an identity vector. + for (unsigned i = 0; i != NumElts; ++i) + Mask.push_back(ConstantUInt::get(Type::UIntTy, i)); + return V; +} + +Instruction *InstCombiner::visitInsertElementInst(InsertElementInst &IE) { + Value *VecOp = IE.getOperand(0); + Value *ScalarOp = IE.getOperand(1); + Value *IdxOp = IE.getOperand(2); + + // If the inserted element was extracted from some other vector, and if the + // indexes are constant, try to turn this into a shufflevector operation. + if (ExtractElementInst *EI = dyn_cast(ScalarOp)) { + if (isa(EI->getOperand(1)) && isa(IdxOp) && + EI->getOperand(0)->getType() == IE.getType()) { + unsigned NumVectorElts = IE.getType()->getNumElements(); + unsigned ExtractedIdx=cast(EI->getOperand(1))->getRawValue(); + unsigned InsertedIdx = cast(IdxOp)->getRawValue(); + + if (ExtractedIdx >= NumVectorElts) // Out of range extract. + return ReplaceInstUsesWith(IE, VecOp); + + if (InsertedIdx >= NumVectorElts) // Out of range insert. + return ReplaceInstUsesWith(IE, UndefValue::get(IE.getType())); + + // If we are extracting a value from a vector, then inserting it right + // back into the same place, just use the input vector. + if (EI->getOperand(0) == VecOp && ExtractedIdx == InsertedIdx) + return ReplaceInstUsesWith(IE, VecOp); + + // We could theoretically do this for ANY input. However, doing so could + // turn chains of insertelement instructions into a chain of shufflevector + // instructions, and right now we do not merge shufflevectors. As such, + // only do this in a situation where it is clear that there is benefit. + if (isa(VecOp) || isa(VecOp)) { + // Turn this into shuffle(EIOp0, VecOp, Mask). The result has all of + // the values of VecOp, except then one read from EIOp0. + // Build a new shuffle mask. + std::vector Mask; + if (isa(VecOp)) + Mask.assign(NumVectorElts, UndefValue::get(Type::UIntTy)); + else { + assert(isa(VecOp) && "Unknown thing"); + Mask.assign(NumVectorElts, ConstantUInt::get(Type::UIntTy, + NumVectorElts)); + } + Mask[InsertedIdx] = ConstantUInt::get(Type::UIntTy, ExtractedIdx); + return new ShuffleVectorInst(EI->getOperand(0), VecOp, + ConstantPacked::get(Mask)); + } + + // If this insertelement isn't used by some other insertelement, turn it + // (and any insertelements it points to), into one big shuffle. + if (!IE.hasOneUse() || !isa(IE.use_back())) { + std::vector Mask; + Value *InVecA = CollectShuffleElements(&IE, Mask, EI->getOperand(0)); + + // We now have a shuffle of InVecA, VecOp, Mask. + return new ShuffleVectorInst(InVecA, EI->getOperand(0), + ConstantPacked::get(Mask)); + } + } + } + + return 0; +} + + Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { Value *LHS = SVI.getOperand(0); Value *RHS = SVI.getOperand(1); @@ -6925,6 +7046,11 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { if (isa(Mask)) return ReplaceInstUsesWith(SVI, UndefValue::get(SVI.getType())); + // TODO: Canonicalize shuffle(undef,x) -> shuffle(x, undef). + + // TODO: If we have shuffle(x, undef, mask) and any elements of mask refer to + // the undef, change them to undefs. + // Canonicalize shuffle(x,x) -> shuffle(x,undef) if (LHS == RHS) { if (isa(LHS)) {