From: Vitaly Buka Date: Tue, 18 Apr 2023 00:19:57 +0000 (-0700) Subject: Revert "[VPlan] Unify Value2VPValue and VPExternalDefs maps (NFCI)." X-Git-Tag: upstream/17.0.6~11272 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8c2276f89887d0a27298a1bbbd2181fa54bbb509;p=platform%2Fupstream%2Fllvm.git Revert "[VPlan] Unify Value2VPValue and VPExternalDefs maps (NFCI)." Asan detects heap-use-after-free, see D147892. This reverts commit 4fc190351e5af901b6107d162d07e1fbca90934f. This reverts commit 668045eb77628be13e448ffbb855473ffca1cc43. --- diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index daebffb..d96daf0 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -8147,7 +8147,7 @@ VPValue *VPRecipeBuilder::createEdgeMask(BasicBlock *Src, BasicBlock *Dst, if (OrigLoop->isLoopExiting(Src)) return EdgeMaskCache[Edge] = SrcMask; - VPValue *EdgeMask = Plan.getVPValueOrAddLiveIn(BI->getCondition()); + VPValue *EdgeMask = Plan.getOrAddVPValue(BI->getCondition()); assert(EdgeMask && "No Edge Mask found for condition"); if (BI->getSuccessor(0) != Dst) @@ -8158,7 +8158,7 @@ VPValue *VPRecipeBuilder::createEdgeMask(BasicBlock *Src, BasicBlock *Dst, // 'select i1 SrcMask, i1 EdgeMask, i1 false'. // The select version does not introduce new UB if SrcMask is false and // EdgeMask is poison. Using 'and' here introduces undefined behavior. - VPValue *False = Plan.getVPValueOrAddLiveIn( + VPValue *False = Plan.getOrAddVPValue( ConstantInt::getFalse(BI->getCondition()->getType())); EdgeMask = Builder.createSelect(SrcMask, EdgeMask, False, BI->getDebugLoc()); @@ -8277,11 +8277,22 @@ VPRecipeBase *VPRecipeBuilder::tryToWidenMemory(Instruction *I, /// Creates a VPWidenIntOrFpInductionRecpipe for \p Phi. If needed, it will also /// insert a recipe to expand the step for the induction recipe. -static VPWidenIntOrFpInductionRecipe * -createWidenInductionRecipes(PHINode *Phi, Instruction *PhiOrTrunc, - VPValue *Start, const InductionDescriptor &IndDesc, - VPlan &Plan, ScalarEvolution &SE, Loop &OrigLoop, - VFRange &Range) { +static VPWidenIntOrFpInductionRecipe *createWidenInductionRecipes( + PHINode *Phi, Instruction *PhiOrTrunc, VPValue *Start, + const InductionDescriptor &IndDesc, LoopVectorizationCostModel &CM, + VPlan &Plan, ScalarEvolution &SE, Loop &OrigLoop, VFRange &Range) { + // Returns true if an instruction \p I should be scalarized instead of + // vectorized for the chosen vectorization factor. + auto ShouldScalarizeInstruction = [&CM](Instruction *I, ElementCount VF) { + return CM.isScalarAfterVectorization(I, VF) || + CM.isProfitableToScalarize(I, VF); + }; + + bool NeedsScalarIVOnly = LoopVectorizationPlanner::getDecisionAndClampRange( + [&](ElementCount VF) { + return ShouldScalarizeInstruction(PhiOrTrunc, VF); + }, + Range); assert(IndDesc.getStartValue() == Phi->getIncomingValueForBlock(OrigLoop.getLoopPreheader())); assert(SE.isLoopInvariant(IndDesc.getStep(), &OrigLoop) && @@ -8290,10 +8301,12 @@ createWidenInductionRecipes(PHINode *Phi, Instruction *PhiOrTrunc, VPValue *Step = vputils::getOrCreateVPValueForSCEVExpr(Plan, IndDesc.getStep(), SE); if (auto *TruncI = dyn_cast(PhiOrTrunc)) { - return new VPWidenIntOrFpInductionRecipe(Phi, Start, Step, IndDesc, TruncI); + return new VPWidenIntOrFpInductionRecipe(Phi, Start, Step, IndDesc, TruncI, + !NeedsScalarIVOnly); } assert(isa(PhiOrTrunc) && "must be a phi node here"); - return new VPWidenIntOrFpInductionRecipe(Phi, Start, Step, IndDesc); + return new VPWidenIntOrFpInductionRecipe(Phi, Start, Step, IndDesc, + !NeedsScalarIVOnly); } VPRecipeBase *VPRecipeBuilder::tryToOptimizeInductionPHI( @@ -8302,7 +8315,7 @@ VPRecipeBase *VPRecipeBuilder::tryToOptimizeInductionPHI( // Check if this is an integer or fp induction. If so, build the recipe that // produces its scalar and vector values. if (auto *II = Legal->getIntOrFpInductionDescriptor(Phi)) - return createWidenInductionRecipes(Phi, Phi, Operands[0], *II, Plan, + return createWidenInductionRecipes(Phi, Phi, Operands[0], *II, CM, Plan, *PSE.getSE(), *OrigLoop, Range); // Check if this is pointer induction. If so, build the recipe for it. @@ -8341,9 +8354,9 @@ VPWidenIntOrFpInductionRecipe *VPRecipeBuilder::tryToOptimizeInductionTruncate( auto *Phi = cast(I->getOperand(0)); const InductionDescriptor &II = *Legal->getIntOrFpInductionDescriptor(Phi); - VPValue *Start = Plan.getVPValueOrAddLiveIn(II.getStartValue()); - return createWidenInductionRecipes(Phi, I, Start, II, Plan, *PSE.getSE(), - *OrigLoop, Range); + VPValue *Start = Plan.getOrAddVPValue(II.getStartValue()); + return createWidenInductionRecipes(Phi, I, Start, II, CM, Plan, + *PSE.getSE(), *OrigLoop, Range); } return nullptr; } @@ -8474,7 +8487,7 @@ VPWidenCallRecipe *VPRecipeBuilder::tryToWidenCall(CallInst *CI, if (Legal->isMaskRequired(CI)) Mask = createBlockInMask(CI->getParent(), *Plan); else - Mask = Plan->getVPValueOrAddLiveIn(ConstantInt::getTrue( + Mask = Plan->getOrAddVPValue(ConstantInt::getTrue( IntegerType::getInt1Ty(Variant->getFunctionType()->getContext()))); VFShape Shape = VFShape::get(*CI, VariantVF, /*HasGlobalPred=*/true); @@ -8526,8 +8539,8 @@ VPRecipeBase *VPRecipeBuilder::tryToWiden(Instruction *I, if (CM.isPredicatedInst(I)) { SmallVector Ops(Operands.begin(), Operands.end()); VPValue *Mask = createBlockInMask(I->getParent(), *Plan); - VPValue *One = Plan->getVPValueOrAddLiveIn( - ConstantInt::get(I->getType(), 1u, false)); + VPValue *One = + Plan->getOrAddExternalDef(ConstantInt::get(I->getType(), 1u, false)); auto *SafeRHS = new VPInstruction(Instruction::Select, {Mask, Ops[1], One}, I->getDebugLoc()); @@ -8748,7 +8761,7 @@ void LoopVectorizationPlanner::buildVPlansWithVPRecipes(ElementCount MinVF, static void addCanonicalIVRecipes(VPlan &Plan, Type *IdxTy, DebugLoc DL, TailFoldingStyle Style) { Value *StartIdx = ConstantInt::get(IdxTy, 0); - auto *StartV = Plan.getVPValueOrAddLiveIn(StartIdx); + auto *StartV = Plan.getOrAddVPValue(StartIdx); // Add a VPCanonicalIVPHIRecipe starting at 0 to the header. auto *CanonicalIVPHI = new VPCanonicalIVPHIRecipe(StartV, DL); @@ -8864,7 +8877,7 @@ static void addUsersInExitBlock(VPBasicBlock *HeaderVPBB, for (PHINode &ExitPhi : ExitBB->phis()) { Value *IncomingValue = ExitPhi.getIncomingValueForBlock(ExitingBB); - VPValue *V = Plan.getVPValueOrAddLiveIn(IncomingValue); + VPValue *V = Plan.getOrAddVPValue(IncomingValue, true); Plan.addLiveOut(&ExitPhi, V); } } @@ -8975,7 +8988,7 @@ std::optional LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes( SmallVector Operands; auto *Phi = dyn_cast(Instr); if (Phi && Phi->getParent() == OrigLoop->getHeader()) { - Operands.push_back(Plan->getVPValueOrAddLiveIn( + Operands.push_back(Plan->getOrAddVPValue( Phi->getIncomingValueForBlock(OrigLoop->getLoopPreheader()))); } else { auto OpRange = Plan->mapToVPValues(Instr->operands()); @@ -10464,7 +10477,7 @@ bool LoopVectorizePass::processLoop(Loop *L) { IndPhi, *ID, {EPI.MainLoopIterationCountCheck}); } assert(ResumeV && "Must have a resume value"); - VPValue *StartVal = BestEpiPlan.getVPValueOrAddLiveIn(ResumeV); + VPValue *StartVal = BestEpiPlan.getOrAddExternalDef(ResumeV); cast(&R)->setStartValue(StartVal); } diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp index f185c9a..4655399 100644 --- a/llvm/lib/Transforms/Vectorize/VPlan.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp @@ -591,12 +591,14 @@ VPlan::~VPlan() { VPBlockBase::deleteCFG(Entry); } - for (VPValue *VPV : VPLiveInsToFree) + for (VPValue *VPV : VPValuesToFree) delete VPV; if (TripCount) delete TripCount; if (BackedgeTakenCount) delete BackedgeTakenCount; + for (auto &P : VPExternalDefs) + delete P.second; } VPActiveLaneMaskPHIRecipe *VPlan::getActiveLaneMaskPhi() { @@ -639,7 +641,7 @@ void VPlan::prepareToExecute(Value *TripCountV, Value *VectorTripCountV, // needs to be changed from zero to the value after the main vector loop. // FIXME: Improve modeling for canonical IV start values in the epilogue loop. if (CanonicalIVStartValue) { - VPValue *VPV = getVPValueOrAddLiveIn(CanonicalIVStartValue); + VPValue *VPV = getOrAddExternalDef(CanonicalIVStartValue); auto *IV = getCanonicalIV(); assert(all_of(IV->users(), [](const VPUser *U) { @@ -1129,9 +1131,9 @@ bool vputils::onlyFirstLaneUsed(VPValue *Def) { VPValue *vputils::getOrCreateVPValueForSCEVExpr(VPlan &Plan, const SCEV *Expr, ScalarEvolution &SE) { if (auto *E = dyn_cast(Expr)) - return Plan.getVPValueOrAddLiveIn(E->getValue()); + return Plan.getOrAddExternalDef(E->getValue()); if (auto *E = dyn_cast(Expr)) - return Plan.getVPValueOrAddLiveIn(E->getValue()); + return Plan.getOrAddExternalDef(E->getValue()); VPBasicBlock *Preheader = Plan.getEntry()->getEntryBasicBlock(); VPExpandSCEVRecipe *Step = new VPExpandSCEVRecipe(Expr, SE); diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h index 3d031e6..ec75c02 100644 --- a/llvm/lib/Transforms/Vectorize/VPlan.h +++ b/llvm/lib/Transforms/Vectorize/VPlan.h @@ -1140,20 +1140,22 @@ class VPWidenIntOrFpInductionRecipe : public VPHeaderPHIRecipe { PHINode *IV; TruncInst *Trunc; const InductionDescriptor &IndDesc; + bool NeedsVectorIV; public: VPWidenIntOrFpInductionRecipe(PHINode *IV, VPValue *Start, VPValue *Step, - const InductionDescriptor &IndDesc) + const InductionDescriptor &IndDesc, + bool NeedsVectorIV) : VPHeaderPHIRecipe(VPDef::VPWidenIntOrFpInductionSC, IV, Start), IV(IV), - Trunc(nullptr), IndDesc(IndDesc) { + Trunc(nullptr), IndDesc(IndDesc), NeedsVectorIV(NeedsVectorIV) { addOperand(Step); } VPWidenIntOrFpInductionRecipe(PHINode *IV, VPValue *Start, VPValue *Step, const InductionDescriptor &IndDesc, - TruncInst *Trunc) + TruncInst *Trunc, bool NeedsVectorIV) : VPHeaderPHIRecipe(VPDef::VPWidenIntOrFpInductionSC, Trunc, Start), - IV(IV), Trunc(Trunc), IndDesc(IndDesc) { + IV(IV), Trunc(Trunc), IndDesc(IndDesc), NeedsVectorIV(NeedsVectorIV) { addOperand(Step); } @@ -1207,6 +1209,9 @@ public: const Type *getScalarType() const { return Trunc ? Trunc->getType() : IV->getType(); } + + /// Returns true if a vector phi needs to be created for the induction. + bool needsVectorIV() const { return NeedsVectorIV; } }; class VPWidenPointerInductionRecipe : public VPHeaderPHIRecipe { @@ -2228,6 +2233,10 @@ class VPlan { /// Holds the name of the VPlan, for printing. std::string Name; + /// Holds all the external definitions created for this VPlan. External + /// definitions must be immutable and hold a pointer to their underlying IR. + DenseMap VPExternalDefs; + /// Represents the trip count of the original loop, for folding /// the tail. VPValue *TripCount = nullptr; @@ -2243,9 +2252,9 @@ class VPlan { /// VPlan. Value2VPValueTy Value2VPValue; - /// Contains all the external definitions created for this VPlan. External - /// definitions are VPValues that hold a pointer to their underlying IR. - SmallVector VPLiveInsToFree; + /// Contains all VPValues that been allocated by addVPValue directly and need + /// to be free when the plan's destructor is called. + SmallVector VPValuesToFree; /// Indicates whether it is safe use the Value2VPValue mapping or if the /// mapping cannot be used any longer, because it is stale. @@ -2325,35 +2334,50 @@ public: void setName(const Twine &newName) { Name = newName.str(); } + /// Get the existing or add a new external definition for \p V. + VPValue *getOrAddExternalDef(Value *V) { + auto I = VPExternalDefs.insert({V, nullptr}); + if (I.second) + I.first->second = new VPValue(V); + return I.first->second; + } + + void addVPValue(Value *V) { + assert(Value2VPValueEnabled && + "IR value to VPValue mapping may be out of date!"); + assert(V && "Trying to add a null Value to VPlan"); + assert(!Value2VPValue.count(V) && "Value already exists in VPlan"); + VPValue *VPV = new VPValue(V); + Value2VPValue[V] = VPV; + VPValuesToFree.push_back(VPV); + } + void addVPValue(Value *V, VPValue *VPV) { - assert((Value2VPValueEnabled || !VPV->getDefiningRecipe()) && - "Value2VPValue mapping may be out of date!"); + assert(Value2VPValueEnabled && "Value2VPValue mapping may be out of date!"); assert(V && "Trying to add a null Value to VPlan"); assert(!Value2VPValue.count(V) && "Value already exists in VPlan"); Value2VPValue[V] = VPV; } /// Returns the VPValue for \p V. \p OverrideAllowed can be used to disable - /// /// checking whether it is safe to query VPValues using IR Values. + /// checking whether it is safe to query VPValues using IR Values. VPValue *getVPValue(Value *V, bool OverrideAllowed = false) { + assert((OverrideAllowed || isa(V) || Value2VPValueEnabled) && + "Value2VPValue mapping may be out of date!"); assert(V && "Trying to get the VPValue of a null Value"); assert(Value2VPValue.count(V) && "Value does not exist in VPlan"); - assert((!Value2VPValue[V]->getDefiningRecipe() || Value2VPValueEnabled || - OverrideAllowed) && - "Value2VPValue mapping may be out of date!"); return Value2VPValue[V]; } - /// Gets the VPValue for \p V or adds a new live-in (if none exists yet) for - /// \p V. - VPValue *getVPValueOrAddLiveIn(Value *V) { + /// Gets the VPValue or adds a new one (if none exists yet) for \p V. \p + /// OverrideAllowed can be used to disable checking whether it is safe to + /// query VPValues using IR Values. + VPValue *getOrAddVPValue(Value *V, bool OverrideAllowed = false) { + assert((OverrideAllowed || isa(V) || Value2VPValueEnabled) && + "Value2VPValue mapping may be out of date!"); assert(V && "Trying to get or add the VPValue of a null Value"); - if (!Value2VPValue.count(V)) { - VPValue *VPV = new VPValue(V); - VPLiveInsToFree.push_back(VPV); - addVPValue(V, VPV); - } - + if (!Value2VPValue.count(V)) + addVPValue(V); return getVPValue(V); } @@ -2379,7 +2403,7 @@ public: iterator_range>> mapToVPValues(User::op_range Operands) { std::function Fn = [this](Value *Op) { - return getVPValueOrAddLiveIn(Op); + return getOrAddVPValue(Op); }; return map_range(Operands, Fn); } diff --git a/llvm/lib/Transforms/Vectorize/VPlanHCFGBuilder.cpp b/llvm/lib/Transforms/Vectorize/VPlanHCFGBuilder.cpp index 10fefae..952ce72 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanHCFGBuilder.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanHCFGBuilder.cpp @@ -196,7 +196,7 @@ VPValue *PlainCFGBuilder::getOrCreateVPOperand(Value *IRVal) { // A and B: Create VPValue and add it to the pool of external definitions and // to the Value->VPValue map. - VPValue *NewVPVal = Plan.getVPValueOrAddLiveIn(IRVal); + VPValue *NewVPVal = Plan.getOrAddExternalDef(IRVal); IRDef2VPValue[IRVal] = NewVPVal; return NewVPVal; } @@ -272,7 +272,7 @@ VPBasicBlock *PlainCFGBuilder::buildPlainCFG() { for (auto &I : *ThePreheaderBB) { if (I.getType()->isVoidTy()) continue; - IRDef2VPValue[&I] = Plan.getVPValueOrAddLiveIn(&I); + IRDef2VPValue[&I] = Plan.getOrAddExternalDef(&I); } // Create empty VPBB for Loop H so that we can link PH->H. VPBlockBase *HeaderVPBB = getOrCreateVPBB(TheLoop->getHeader()); diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp index c657b76..8aa968f 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp @@ -52,10 +52,11 @@ void VPlanTransforms::VPInstructionsToVPRecipes( if (auto *VPPhi = dyn_cast(&Ingredient)) { auto *Phi = cast(VPPhi->getUnderlyingValue()); if (const auto *II = GetIntOrFpInductionDescriptor(Phi)) { - VPValue *Start = Plan->getVPValueOrAddLiveIn(II->getStartValue()); + VPValue *Start = Plan->getOrAddVPValue(II->getStartValue()); VPValue *Step = vputils::getOrCreateVPValueForSCEVExpr(*Plan, II->getStep(), SE); - NewRecipe = new VPWidenIntOrFpInductionRecipe(Phi, Start, Step, *II); + NewRecipe = + new VPWidenIntOrFpInductionRecipe(Phi, Start, Step, *II, true); } else { Plan->addVPValue(Phi, VPPhi); continue; @@ -67,15 +68,13 @@ void VPlanTransforms::VPInstructionsToVPRecipes( // Create VPWidenMemoryInstructionRecipe for loads and stores. if (LoadInst *Load = dyn_cast(Inst)) { NewRecipe = new VPWidenMemoryInstructionRecipe( - *Load, - Plan->getVPValueOrAddLiveIn(getLoadStorePointerOperand(Inst)), + *Load, Plan->getOrAddVPValue(getLoadStorePointerOperand(Inst)), nullptr /*Mask*/, false /*Consecutive*/, false /*Reverse*/); } else if (StoreInst *Store = dyn_cast(Inst)) { NewRecipe = new VPWidenMemoryInstructionRecipe( - *Store, - Plan->getVPValueOrAddLiveIn(getLoadStorePointerOperand(Inst)), - Plan->getVPValueOrAddLiveIn(Store->getValueOperand()), - nullptr /*Mask*/, false /*Consecutive*/, false /*Reverse*/); + *Store, Plan->getOrAddVPValue(getLoadStorePointerOperand(Inst)), + Plan->getOrAddVPValue(Store->getValueOperand()), nullptr /*Mask*/, + false /*Consecutive*/, false /*Reverse*/); } else if (GetElementPtrInst *GEP = dyn_cast(Inst)) { NewRecipe = new VPWidenGEPRecipe(GEP, Plan->mapToVPValues(GEP->operands())); @@ -473,10 +472,7 @@ void VPlanTransforms::removeRedundantCanonicalIVs(VPlan &Plan) { // everything WidenNewIV's users need. That is, WidenOriginalIV will // generate a vector phi or all users of WidenNewIV demand the first lane // only. - if (any_of(WidenOriginalIV->users(), - [WidenOriginalIV](VPUser *U) { - return !U->usesScalars(WidenOriginalIV); - }) || + if (WidenOriginalIV->needsVectorIV() || vputils::onlyFirstLaneUsed(WidenNewIV)) { WidenNewIV->replaceAllUsesWith(WidenOriginalIV); WidenNewIV->eraseFromParent(); @@ -604,9 +600,9 @@ void VPlanTransforms::optimizeForVFAndUF(VPlan &Plan, ElementCount BestVF, return; LLVMContext &Ctx = SE.getContext(); - auto *BOC = new VPInstruction( - VPInstruction::BranchOnCond, - {Plan.getVPValueOrAddLiveIn(ConstantInt::getTrue(Ctx))}); + auto *BOC = + new VPInstruction(VPInstruction::BranchOnCond, + {Plan.getOrAddExternalDef(ConstantInt::getTrue(Ctx))}); Term->eraseFromParent(); ExitingVPBB->appendRecipe(BOC); Plan.setVF(BestVF); diff --git a/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp index f6f283a..e8c84cc 100644 --- a/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp @@ -96,7 +96,7 @@ TEST_F(VPlanHCFGTest, testBuildHCFGInnerLoop) { #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) // Add an external value to check we do not print the list of external values, // as this is not required with the new printing. - Plan->getVPValueOrAddLiveIn(&*F->arg_begin()); + Plan->addVPValue(&*F->arg_begin()); std::string FullDump; raw_string_ostream OS(FullDump); Plan->printDOT(OS); diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp index 606d8d0..903e823 100644 --- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp @@ -1203,8 +1203,8 @@ TEST(VPRecipeTest, dump) { BinaryOperator::CreateAdd(UndefValue::get(Int32), UndefValue::get(Int32)); AI->setName("a"); SmallVector Args; - VPValue *ExtVPV1 = Plan.getVPValueOrAddLiveIn(ConstantInt::get(Int32, 1)); - VPValue *ExtVPV2 = Plan.getVPValueOrAddLiveIn(ConstantInt::get(Int32, 2)); + VPValue *ExtVPV1 = Plan.getOrAddExternalDef(ConstantInt::get(Int32, 1)); + VPValue *ExtVPV2 = Plan.getOrAddExternalDef(ConstantInt::get(Int32, 2)); Args.push_back(ExtVPV1); Args.push_back(ExtVPV2); VPWidenRecipe *WidenR =