diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h --- a/llvm/lib/Transforms/Vectorize/VPlan.h +++ b/llvm/lib/Transforms/Vectorize/VPlan.h @@ -606,46 +606,23 @@ /// VPRecipeBase is a base class modeling a sequence of one or more output IR /// instructions. -class VPRecipeBase : public ilist_node_with_parent { +class VPRecipeBase : public ilist_node_with_parent, + public VPDef { friend VPBasicBlock; friend class VPBlockUtils; - const unsigned char SubclassID; ///< Subclass identifier (for isa/dyn_cast). /// Each VPRecipe belongs to a single VPBasicBlock. VPBasicBlock *Parent = nullptr; public: - /// An enumeration for keeping track of the concrete subclass of VPRecipeBase - /// that is actually instantiated. Values of this enumeration are kept in the - /// SubclassID field of the VPRecipeBase objects. They are used for concrete - /// type identification. - using VPRecipeTy = enum { - VPBlendSC, - VPBranchOnMaskSC, - VPInstructionSC, - VPInterleaveSC, - VPPredInstPHISC, - VPReductionSC, - VPReplicateSC, - VPWidenCallSC, - VPWidenCanonicalIVSC, - VPWidenGEPSC, - VPWidenIntOrFpInductionSC, - VPWidenMemoryInstructionSC, - VPWidenPHISC, - VPWidenSC, - VPWidenSelectSC - }; - - VPRecipeBase(const unsigned char SC) : SubclassID(SC) {} + VPRecipeBase(const unsigned char SC, ArrayRef Operands = {}) + : VPDef(SC, Operands) {} + template + VPRecipeBase(const unsigned char SC, iterator_range Operands) + : VPDef(SC, Operands) {} virtual ~VPRecipeBase() = default; - /// \return an ID for the concrete type of this object. - /// This is used to implement the classof checks. This should not be used - /// for any other purpose, as the values may change as LLVM evolves. - unsigned getVPRecipeID() const { return SubclassID; } - /// \return the VPBasicBlock which this VPRecipe belongs to. VPBasicBlock *getParent() { return Parent; } const VPBasicBlock *getParent() const { return Parent; } @@ -682,47 +659,47 @@ /// \returns an iterator pointing to the element after the erased one iplist::iterator eraseFromParent(); - /// Returns a pointer to a VPUser, if the recipe inherits from VPUser or - /// nullptr otherwise. - VPUser *toVPUser(); - /// Returns a pointer to a VPValue, if the recipe inherits from VPValue or /// nullptr otherwise. VPValue *toVPValue(); const VPValue *toVPValue() const; + /// Returns a pointer to a VPUser, if the recipe inherits from VPUser or + /// nullptr otherwise. + VPUser *toVPUser(); + /// Returns the underlying instruction, if the recipe is a VPValue or nullptr /// otherwise. Instruction *getUnderlyingInstr() { - if (auto *VPV = toVPValue()) - return cast_or_null(VPV->getUnderlyingValue()); + if (getNumDefinedValues() == 1) + return cast_or_null(getVPValue()->getUnderlyingValue()); return nullptr; } const Instruction *getUnderlyingInstr() const { - if (auto *VPV = toVPValue()) - return cast_or_null(VPV->getUnderlyingValue()); + if (getNumDefinedValues() == 1) + return cast_or_null(getVPValue()->getUnderlyingValue()); return nullptr; } }; -inline bool VPUser::classof(const VPRecipeBase *Recipe) { - return Recipe->getVPRecipeID() == VPRecipeBase::VPInstructionSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPWidenSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPWidenCallSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPWidenSelectSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPWidenGEPSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPBlendSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPInterleaveSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPReplicateSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPBranchOnMaskSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPWidenMemoryInstructionSC; +inline bool VPUser::classof(const VPDef *Recipe) { + return Recipe->getVPDefID() == VPRecipeBase::VPInstructionSC || + Recipe->getVPDefID() == VPRecipeBase::VPWidenSC || + Recipe->getVPDefID() == VPRecipeBase::VPWidenCallSC || + Recipe->getVPDefID() == VPRecipeBase::VPWidenSelectSC || + Recipe->getVPDefID() == VPRecipeBase::VPWidenGEPSC || + Recipe->getVPDefID() == VPRecipeBase::VPBlendSC || + Recipe->getVPDefID() == VPRecipeBase::VPInterleaveSC || + Recipe->getVPDefID() == VPRecipeBase::VPReplicateSC || + Recipe->getVPDefID() == VPRecipeBase::VPBranchOnMaskSC || + Recipe->getVPDefID() == VPRecipeBase::VPWidenMemoryInstructionSC; } /// This is a concrete Recipe that models a single VPlan-level instruction. /// While as any Recipe it may generate a sequence of IR instructions when /// executed, these instructions would always form a single-def expression as /// the VPInstruction is also a single def-use vertex. -class VPInstruction : public VPUser, public VPValue, public VPRecipeBase { +class VPInstruction : public VPValue, public VPRecipeBase { friend class VPlanSlp; public: @@ -748,8 +725,15 @@ public: VPInstruction(unsigned Opcode, ArrayRef Operands) - : VPUser(Operands), VPValue(VPValue::VPInstructionSC), - VPRecipeBase(VPRecipeBase::VPInstructionSC), Opcode(Opcode) {} + : VPValue(VPValue::VPInstructionSC), + VPRecipeBase(VPRecipeBase::VPInstructionSC, Operands), Opcode(Opcode) {} + + VPInstruction(unsigned Opcode, ArrayRef Operands) + : VPValue(VPValue::VPInstructionSC), + VPRecipeBase(VPRecipeBase::VPInstructionSC, {}), Opcode(Opcode) { + for (auto *I : Operands) + addOperand(I->getVPValue()); + } VPInstruction(unsigned Opcode, std::initializer_list Operands) : VPInstruction(Opcode, ArrayRef(Operands)) {} @@ -765,8 +749,8 @@ } /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *R) { - return R->getVPRecipeID() == VPRecipeBase::VPInstructionSC; + static inline bool classof(const VPDef *R) { + return R->getVPDefID() == VPRecipeBase::VPInstructionSC; } unsigned getOpcode() const { return Opcode; } @@ -816,20 +800,22 @@ /// VPWidenRecipe is a recipe for producing a copy of vector type its /// ingredient. This recipe covers most of the traditional vectorization cases /// where each ingredient transforms into a vectorized version of itself. -class VPWidenRecipe : public VPRecipeBase, public VPUser { +class VPWidenRecipe : public VPRecipeBase { /// Hold the instruction to be widened. Instruction &Ingredient; public: template VPWidenRecipe(Instruction &I, iterator_range Operands) - : VPRecipeBase(VPWidenSC), VPUser(Operands), Ingredient(I) {} + : VPRecipeBase(VPWidenSC, Operands), Ingredient(I) { + new VPValue(&I, this); + } ~VPWidenRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPWidenSC; } /// Produce widened copies of all Ingredients. @@ -841,20 +827,20 @@ }; /// A recipe for widening Call instructions. -class VPWidenCallRecipe : public VPRecipeBase, public VPDef { +class VPWidenCallRecipe : public VPRecipeBase { public: template VPWidenCallRecipe(CallInst &I, iterator_range CallArguments) - : VPRecipeBase(VPRecipeBase::VPWidenCallSC), VPDef(CallArguments) { + : VPRecipeBase(VPRecipeBase::VPWidenCallSC, CallArguments) { new VPValue(&I, this); } ~VPWidenCallRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenCallSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPWidenCallSC; } /// Produce a widened version of the call instruction. @@ -866,7 +852,7 @@ }; /// A recipe for widening select instructions. -class VPWidenSelectRecipe : public VPRecipeBase, public VPDef { +class VPWidenSelectRecipe : public VPRecipeBase { /// Is the condition of the select loop invariant? bool InvariantCond; @@ -875,7 +861,7 @@ template VPWidenSelectRecipe(SelectInst &I, iterator_range Operands, bool InvariantCond) - : VPRecipeBase(VPRecipeBase::VPWidenSelectSC), VPDef(Operands), + : VPRecipeBase(VPRecipeBase::VPWidenSelectSC, Operands), InvariantCond(InvariantCond) { new VPValue(&I, this); } @@ -883,8 +869,8 @@ ~VPWidenSelectRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenSelectSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPWidenSelectSC; } /// Produce a widened version of the select instruction. @@ -896,23 +882,22 @@ }; /// A recipe for handling GEP instructions. -class VPWidenGEPRecipe : public VPRecipeBase, public VPDef { +class VPWidenGEPRecipe : public VPRecipeBase { bool IsPtrLoopInvariant; SmallBitVector IsIndexLoopInvariant; public: template VPWidenGEPRecipe(GetElementPtrInst *GEP, iterator_range Operands) - : VPRecipeBase(VPRecipeBase::VPWidenGEPSC), VPDef(Operands), + : VPRecipeBase(VPRecipeBase::VPWidenGEPSC, Operands), IsIndexLoopInvariant(GEP->getNumIndices(), false) { - new VPValue(GEP, this); } template VPWidenGEPRecipe(GetElementPtrInst *GEP, iterator_range Operands, Loop *OrigLoop) - : VPRecipeBase(VPWidenGEPSC), VPDef(Operands), + : VPRecipeBase(VPWidenGEPSC, Operands), IsIndexLoopInvariant(GEP->getNumIndices(), false) { new VPValue(GEP, this); IsPtrLoopInvariant = OrigLoop->isLoopInvariant(GEP->getPointerOperand()); @@ -923,8 +908,8 @@ ~VPWidenGEPRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenGEPSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPWidenGEPSC; } /// Generate the gep nodes. @@ -943,12 +928,14 @@ public: VPWidenIntOrFpInductionRecipe(PHINode *IV, TruncInst *Trunc = nullptr) - : VPRecipeBase(VPWidenIntOrFpInductionSC), IV(IV), Trunc(Trunc) {} + : VPRecipeBase(VPWidenIntOrFpInductionSC), IV(IV), Trunc(Trunc) { + new VPValue(IV, this); + } ~VPWidenIntOrFpInductionRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenIntOrFpInductionSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPWidenIntOrFpInductionSC; } /// Generate the vectorized and scalarized versions of the phi node as @@ -965,12 +952,14 @@ PHINode *Phi; public: - VPWidenPHIRecipe(PHINode *Phi) : VPRecipeBase(VPWidenPHISC), Phi(Phi) {} + VPWidenPHIRecipe(PHINode *Phi) : VPRecipeBase(VPWidenPHISC), Phi(Phi) { + new VPValue(Phi, this); + } ~VPWidenPHIRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenPHISC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPWidenPHISC; } /// Generate the phi/select nodes. @@ -983,7 +972,7 @@ /// A recipe for vectorizing a phi-node as a sequence of mask-based select /// instructions. -class VPBlendRecipe : public VPRecipeBase, public VPUser { +class VPBlendRecipe : public VPRecipeBase { PHINode *Phi; public: @@ -991,7 +980,8 @@ /// respective masks, ordered [I0, M0, I1, M1, ...]. Note that a single value /// might be incoming with a full mask for which there is no VPValue. VPBlendRecipe(PHINode *Phi, ArrayRef Operands) - : VPRecipeBase(VPBlendSC), VPUser(Operands), Phi(Phi) { + : VPRecipeBase(VPBlendSC, Operands), Phi(Phi) { + new VPValue(Phi, this); assert(Operands.size() > 0 && ((Operands.size() == 1) || (Operands.size() % 2 == 0)) && "Expected either a single incoming value or a positive even number " @@ -999,8 +989,8 @@ } /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPBlendSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPBlendSC; } /// Return the number of incoming values, taking into account that a single @@ -1023,13 +1013,13 @@ /// VPInterleaveRecipe is a recipe for transforming an interleave group of load /// or stores into one wide load/store and shuffles. -class VPInterleaveRecipe : public VPRecipeBase, public VPDef { +class VPInterleaveRecipe : public VPRecipeBase { const InterleaveGroup *IG; public: VPInterleaveRecipe(const InterleaveGroup *IG, VPValue *Addr, VPValue *Mask) - : VPRecipeBase(VPInterleaveSC), VPDef(Addr), IG(IG) { + : VPRecipeBase(VPInterleaveSC, Addr), IG(IG) { for (unsigned i = 0; i < IG->getFactor(); ++i) if (Instruction *I = IG->getMember(i)) { if (I->getType()->isVoidTy()) @@ -1043,8 +1033,8 @@ ~VPInterleaveRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPInterleaveSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPInterleaveSC; } /// Return the address accessed by this recipe. @@ -1092,13 +1082,15 @@ VPValue *VecOp, VPValue *CondOp, bool NoNaN, const TargetTransformInfo *TTI) : VPRecipeBase(VPReductionSC), RdxDesc(R), I(I), VecOp(VecOp), - ChainOp(ChainOp), CondOp(CondOp), NoNaN(NoNaN), TTI(TTI) {} + ChainOp(ChainOp), CondOp(CondOp), NoNaN(NoNaN), TTI(TTI) { + new VPValue(I, this); + } ~VPReductionRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPReductionSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPReductionSC; } /// Generate the reduction in the loop @@ -1113,7 +1105,7 @@ /// copies of the original scalar type, one per lane, instead of producing a /// single copy of widened type for all lanes. If the instruction is known to be /// uniform only one copy, per lane zero, will be generated. -class VPReplicateRecipe : public VPRecipeBase, public VPUser { +class VPReplicateRecipe : public VPRecipeBase { /// The instruction being replicated. Instruction *Ingredient; @@ -1130,7 +1122,7 @@ template VPReplicateRecipe(Instruction *I, iterator_range Operands, bool IsUniform, bool IsPredicated = false) - : VPRecipeBase(VPReplicateSC), VPUser(Operands), Ingredient(I), + : VPRecipeBase(VPReplicateSC, Operands), Ingredient(I), IsUniform(IsUniform), IsPredicated(IsPredicated) { // Retain the previous behavior of predicateInstructions(), where an // insert-element of a predicated instruction got hoisted into the @@ -1138,13 +1130,14 @@ // having predicated instructions also pack their values into a vector by // default unless they have a replicated user which uses their scalar value. AlsoPack = IsPredicated && !I->use_empty(); + new VPValue(I, this); } ~VPReplicateRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPReplicateSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPReplicateSC; } /// Generate replicas of the desired Ingredient. Replicas will be generated @@ -1160,16 +1153,17 @@ }; /// A recipe for generating conditional branches on the bits of a mask. -class VPBranchOnMaskRecipe : public VPRecipeBase, public VPUser { +class VPBranchOnMaskRecipe : public VPRecipeBase { public: VPBranchOnMaskRecipe(VPValue *BlockInMask) : VPRecipeBase(VPBranchOnMaskSC) { + new VPValue(nullptr, this); if (BlockInMask) // nullptr means all-one mask. addOperand(BlockInMask); } /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPBranchOnMaskSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPBranchOnMaskSC; } /// Generate the extraction of the appropriate bit from the block mask and the @@ -1208,12 +1202,14 @@ /// Construct a VPPredInstPHIRecipe given \p PredInst whose value needs a phi /// nodes after merging back from a Branch-on-Mask. VPPredInstPHIRecipe(Instruction *PredInst) - : VPRecipeBase(VPPredInstPHISC), PredInst(PredInst) {} + : VPRecipeBase(VPPredInstPHISC), PredInst(PredInst) { + new VPValue(PredInst, this); + } ~VPPredInstPHIRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPPredInstPHISC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPPredInstPHISC; } /// Generates phi nodes for live-outs as needed to retain SSA form. @@ -1230,7 +1226,7 @@ /// - For store: Address, stored value, optional mask /// TODO: We currently execute only per-part unless a specific instance is /// provided. -class VPWidenMemoryInstructionRecipe : public VPRecipeBase, public VPDef { +class VPWidenMemoryInstructionRecipe : public VPRecipeBase { Instruction &Instr; void setMask(VPValue *Mask) { @@ -1245,21 +1241,21 @@ public: VPWidenMemoryInstructionRecipe(LoadInst &Load, VPValue *Addr, VPValue *Mask) - : VPRecipeBase(VPWidenMemoryInstructionSC), VPDef({Addr}), Instr(Load) { + : VPRecipeBase(VPWidenMemoryInstructionSC, {Addr}), Instr(Load) { new VPValue(&Load, this); setMask(Mask); } VPWidenMemoryInstructionRecipe(StoreInst &Store, VPValue *Addr, VPValue *StoredValue, VPValue *Mask) - : VPRecipeBase(VPWidenMemoryInstructionSC), VPDef({Addr, StoredValue}), + : VPRecipeBase(VPWidenMemoryInstructionSC, {Addr, StoredValue}), Instr(Store) { setMask(Mask); } /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenMemoryInstructionSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPWidenMemoryInstructionSC; } /// Return the address accessed by this recipe. @@ -1292,21 +1288,16 @@ /// A Recipe for widening the canonical induction variable of the vector loop. class VPWidenCanonicalIVRecipe : public VPRecipeBase { - /// A VPValue representing the canonical vector IV. - VPValue Val; - public: - VPWidenCanonicalIVRecipe() : VPRecipeBase(VPWidenCanonicalIVSC) {} - ~VPWidenCanonicalIVRecipe() override = default; + VPWidenCanonicalIVRecipe() : VPRecipeBase(VPWidenCanonicalIVSC) { + new VPValue(nullptr, this); + } - /// Return the VPValue representing the canonical vector induction variable of - /// the vector loop. - const VPValue *getVPValue() const { return &Val; } - VPValue *getVPValue() { return &Val; } + ~VPWidenCanonicalIVRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenCanonicalIVSC; + static inline bool classof(const VPDef *V) { + return V->getVPDefID() == VPRecipeBase::VPWidenCanonicalIVSC; } /// Generate a canonical vector induction variable of the vector loop, with diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h --- a/llvm/lib/Transforms/Vectorize/VPlanValue.h +++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h @@ -32,7 +32,7 @@ class Value; class VPSlotTracker; class VPUser; -class VPValue; +class VPDef; class VPRecipeBase; class VPDef; @@ -48,6 +48,8 @@ friend class VPSlotTracker; friend class VPRecipeBase; friend class VPDef; + friend class VPInstruction; + friend class VPDef; const unsigned char SubclassID; ///< Subclass identifier (for isa/dyn_cast). @@ -225,20 +227,45 @@ } /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *Recipe); + static inline bool classof(const VPDef *Recipe); }; class VPDef : public VPUser { + const unsigned char SubclassID; ///< Subclass identifier (for isa/dyn_cast). TinyPtrVector DefinedValues; public: - VPDef(std::initializer_list Operands) - : VPDef(ArrayRef(Operands)) {} + /// An enumeration for keeping track of the concrete subclass of VPRecipeBase + /// that is actually instantiated. Values of this enumeration are kept in the + /// SubclassID field of the VPRecipeBase objects. They are used for concrete + /// type identification. + using VPRecipeTy = enum { + VPBlendSC, + VPBranchOnMaskSC, + VPInstructionSC, + VPInterleaveSC, + VPPredInstPHISC, + VPReductionSC, + VPReplicateSC, + VPWidenCallSC, + VPWidenCanonicalIVSC, + VPWidenGEPSC, + VPWidenIntOrFpInductionSC, + VPWidenMemoryInstructionSC, + VPWidenPHISC, + VPWidenSC, + VPWidenSelectSC + }; - VPDef(ArrayRef Operands) : VPUser(Operands) {} + VPDef(const unsigned char SC, std::initializer_list Operands) + : VPDef(SC, ArrayRef(Operands)) {} + + VPDef(const unsigned char SC, ArrayRef Operands) + : VPUser(Operands), SubclassID(SC) {} template - VPDef(iterator_range Operands) : VPUser(Operands) {} + VPDef(const unsigned char SC, iterator_range Operands) + : VPUser(Operands), SubclassID(SC) {} virtual ~VPDef() { for (VPValue *D : DefinedValues) { @@ -253,6 +280,7 @@ assert(DefinedValues[i]); return DefinedValues[i]; } + const VPValue *getVPValue(unsigned i = 0) const { assert(DefinedValues[i]); return DefinedValues[i]; @@ -261,6 +289,11 @@ ArrayRef defined_values() { return DefinedValues; } unsigned getNumDefinedValues() const { return DefinedValues.size(); } + + /// \return an ID for the concrete type of this object. + /// This is used to implement the classof checks. This should not be used + /// for any other purpose, as the values may change as LLVM evolves. + unsigned getVPDefID() const { return SubclassID; } }; class VPlan; diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp --- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp @@ -524,7 +524,7 @@ struct VPMultiDef : public VPDef { SmallVector Defs; - VPMultiDef() : VPDef({}) { + VPMultiDef() : VPDef(0, {}) { new VPValue(nullptr, this); new VPValue(nullptr, this); }