diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp index e58b49a64737..601c406290b2 100644 --- a/llvm/lib/Transforms/Vectorize/VPlan.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp @@ -120,50 +120,18 @@ VPUser *VPRecipeBase::toVPUser() { } VPValue *VPRecipeBase::toVPValue() { + if (getNumDefinedValues() == 1) + return getVPValue(); if (auto *V = dyn_cast(this)) return V; - if (auto *V = dyn_cast(this)) - return V; - if (auto *V = dyn_cast(this)) { - if (!V->isStore()) - return V->getVPValue(); - else - return nullptr; - } - if (auto *V = dyn_cast(this)) - return V; - if (auto *V = dyn_cast(this)) - return V; - if (auto *V = dyn_cast(this)) - return V; - if (auto *V = dyn_cast(this)) - return V; - if (auto *V = dyn_cast(this)) - return V; return nullptr; } const VPValue *VPRecipeBase::toVPValue() const { + if (getNumDefinedValues() == 1) + return getVPValue(); if (auto *V = dyn_cast(this)) return V; - if (auto *V = dyn_cast(this)) - return V; - if (auto *V = dyn_cast(this)) { - if (!V->isStore()) - return V->getVPValue(); - else - return nullptr; - } - if (auto *V = dyn_cast(this)) - return V; - if (auto *V = dyn_cast(this)) - return V; - if (auto *V = dyn_cast(this)) - return V; - if (auto *V = dyn_cast(this)) - return V; - if (auto *V = dyn_cast(this)) - return V; return nullptr; } diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h index 37f1e9e73c39..ecb7004121a2 100644 --- a/llvm/lib/Transforms/Vectorize/VPlan.h +++ b/llvm/lib/Transforms/Vectorize/VPlan.h @@ -620,47 +620,23 @@ public: }; /// VPRecipeBase is a base class modeling a sequence of one or more output IR -/// instructions. -class VPRecipeBase : public ilist_node_with_parent { +/// instructions. VPRecipeBase owns the the VPValues it defines through VPDef +/// and is responsible for deleting its defined values. Single-value +/// VPRecipeBases that also inherit from VPValue must make sure to inherit from +/// VPRecipeBase before VPValue. +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) : VPDef(SC) {} 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; } @@ -718,27 +694,33 @@ public: return cast_or_null(VPV->getUnderlyingValue()); return nullptr; } + + /// Method to support type inquiry through isa, cast, and dyn_cast. + static inline bool classof(const VPDef *D) { + // All VPDefs are also VPRecipeBases. + return true; + } }; -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::VPReductionSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPBranchOnMaskSC || - Recipe->getVPRecipeID() == VPRecipeBase::VPWidenMemoryInstructionSC; +inline bool VPUser::classof(const VPDef *Def) { + return Def->getVPDefID() == VPRecipeBase::VPInstructionSC || + Def->getVPDefID() == VPRecipeBase::VPWidenSC || + Def->getVPDefID() == VPRecipeBase::VPWidenCallSC || + Def->getVPDefID() == VPRecipeBase::VPWidenSelectSC || + Def->getVPDefID() == VPRecipeBase::VPWidenGEPSC || + Def->getVPDefID() == VPRecipeBase::VPBlendSC || + Def->getVPDefID() == VPRecipeBase::VPInterleaveSC || + Def->getVPDefID() == VPRecipeBase::VPReplicateSC || + Def->getVPDefID() == VPRecipeBase::VPReductionSC || + Def->getVPDefID() == VPRecipeBase::VPBranchOnMaskSC || + Def->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 VPUser, public VPRecipeBase { friend class VPlanSlp; public: @@ -764,9 +746,16 @@ protected: public: VPInstruction(unsigned Opcode, ArrayRef Operands) - : VPUser(Operands), VPValue(VPValue::VPVInstructionSC), + : VPValue(VPValue::VPVInstructionSC), VPUser(Operands), VPRecipeBase(VPRecipeBase::VPInstructionSC), Opcode(Opcode) {} + VPInstruction(unsigned Opcode, ArrayRef Operands) + : VPValue(VPValue::VPVInstructionSC), VPUser({}), + VPRecipeBase(VPRecipeBase::VPInstructionSC), Opcode(Opcode) { + for (auto *I : Operands) + addOperand(I->getVPValue()); + } + VPInstruction(unsigned Opcode, std::initializer_list Operands) : VPInstruction(Opcode, ArrayRef(Operands)) {} @@ -781,8 +770,8 @@ public: } /// 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; } @@ -836,14 +825,14 @@ class VPWidenRecipe : public VPRecipeBase, public VPValue, public VPUser { public: template VPWidenRecipe(Instruction &I, iterator_range Operands) - : VPRecipeBase(VPRecipeBase::VPWidenSC), VPValue(VPValue::VPVWidenSC, &I), - VPUser(Operands) {} + : VPRecipeBase(VPRecipeBase::VPWidenSC), + VPValue(VPValue::VPVWidenSC, &I, this), VPUser(Operands) {} ~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 *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenSC; } static inline bool classof(const VPValue *V) { return V->getVPValueID() == VPValue::VPVWidenSC; @@ -858,10 +847,7 @@ public: }; /// A recipe for widening Call instructions. -class VPWidenCallRecipe : public VPRecipeBase, - public VPDef, - public VPUser, - public VPValue { +class VPWidenCallRecipe : public VPRecipeBase, public VPUser, public VPValue { public: template @@ -872,8 +858,8 @@ public: ~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 *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenCallSC; } /// Produce a widened version of the call instruction. @@ -885,10 +871,7 @@ public: }; /// A recipe for widening select instructions. -class VPWidenSelectRecipe : public VPRecipeBase, - public VPDef, - public VPUser, - public VPValue { +class VPWidenSelectRecipe : public VPRecipeBase, public VPUser, public VPValue { /// Is the condition of the select loop invariant? bool InvariantCond; @@ -904,8 +887,8 @@ public: ~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 *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenSelectSC; } /// Produce a widened version of the select instruction. @@ -918,7 +901,6 @@ public: /// A recipe for handling GEP instructions. class VPWidenGEPRecipe : public VPRecipeBase, - public VPDef, public VPUser, public VPValue { bool IsPtrLoopInvariant; @@ -945,8 +927,8 @@ public: ~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 *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenGEPSC; } /// Generate the gep nodes. @@ -965,12 +947,17 @@ class VPWidenIntOrFpInductionRecipe : public VPRecipeBase { public: VPWidenIntOrFpInductionRecipe(PHINode *IV, TruncInst *Trunc = nullptr) - : VPRecipeBase(VPWidenIntOrFpInductionSC), IV(IV), Trunc(Trunc) {} + : VPRecipeBase(VPWidenIntOrFpInductionSC), IV(IV), Trunc(Trunc) { + if (Trunc) + new VPValue(Trunc, this); + else + 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 *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenIntOrFpInductionSC; } /// Generate the vectorized and scalarized versions of the phi node as @@ -987,12 +974,14 @@ class VPWidenPHIRecipe : public VPRecipeBase { 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 *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenPHISC; } /// Generate the phi/select nodes. @@ -1014,6 +1003,7 @@ public: /// might be incoming with a full mask for which there is no VPValue. VPBlendRecipe(PHINode *Phi, ArrayRef Operands) : VPRecipeBase(VPBlendSC), VPUser(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 " @@ -1021,8 +1011,8 @@ public: } /// 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 *D) { + return D->getVPDefID() == VPRecipeBase::VPBlendSC; } /// Return the number of incoming values, taking into account that a single @@ -1047,7 +1037,7 @@ public: /// or stores into one wide load/store and shuffles. The first operand of a /// VPInterleave recipe is the address, followed by the stored values, followed /// by an optional mask. -class VPInterleaveRecipe : public VPRecipeBase, public VPDef, public VPUser { +class VPInterleaveRecipe : public VPRecipeBase, public VPUser { const InterleaveGroup *IG; bool HasMask = false; @@ -1073,8 +1063,8 @@ public: ~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 *D) { + return D->getVPDefID() == VPRecipeBase::VPInterleaveSC; } /// Return the address accessed by this recipe. @@ -1111,7 +1101,7 @@ public: /// A recipe to represent inloop reduction operations, performing a reduction on /// a vector operand into a scalar value, and adding the result to a chain. /// The Operands are {ChainOp, VecOp, [Condition]}. -class VPReductionRecipe : public VPRecipeBase, public VPValue, public VPUser { +class VPReductionRecipe : public VPRecipeBase, public VPUser, public VPValue { /// The recurrence decriptor for the reduction in question. RecurrenceDescriptor *RdxDesc; /// Fast math flags to use for the resulting reduction operation. @@ -1123,9 +1113,9 @@ public: VPReductionRecipe(RecurrenceDescriptor *R, Instruction *I, VPValue *ChainOp, VPValue *VecOp, VPValue *CondOp, bool NoNaN, const TargetTransformInfo *TTI) - : VPRecipeBase(VPRecipeBase::VPReductionSC), - VPValue(VPValue::VPVReductionSC, I), VPUser({ChainOp, VecOp}), - RdxDesc(R), NoNaN(NoNaN), TTI(TTI) { + : VPRecipeBase(VPRecipeBase::VPReductionSC), VPUser({ChainOp, VecOp}), + VPValue(VPValue::VPVReductionSC, I, this), RdxDesc(R), NoNaN(NoNaN), + TTI(TTI) { if (CondOp) addOperand(CondOp); } @@ -1136,8 +1126,9 @@ public: static inline bool classof(const VPValue *V) { return V->getVPValueID() == VPValue::VPVReductionSC; } - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPReductionSC; + + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPReductionSC; } /// Generate the reduction in the loop @@ -1176,7 +1167,7 @@ public: VPReplicateRecipe(Instruction *I, iterator_range Operands, bool IsUniform, bool IsPredicated = false) : VPRecipeBase(VPReplicateSC), VPUser(Operands), - VPValue(VPVReplicateSC, I), IsUniform(IsUniform), + VPValue(VPVReplicateSC, I, this), IsUniform(IsUniform), IsPredicated(IsPredicated) { // Retain the previous behavior of predicateInstructions(), where an // insert-element of a predicated instruction got hoisted into the @@ -1189,8 +1180,8 @@ public: ~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 *D) { + return D->getVPDefID() == VPRecipeBase::VPReplicateSC; } static inline bool classof(const VPValue *V) { @@ -1220,8 +1211,8 @@ public: } /// 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 *D) { + return D->getVPDefID() == VPRecipeBase::VPBranchOnMaskSC; } /// Generate the extraction of the appropriate bit from the block mask and the @@ -1259,12 +1250,14 @@ public: /// Construct a VPPredInstPHIRecipe given \p PredInst whose value needs a phi /// nodes after merging back from a Branch-on-Mask. VPPredInstPHIRecipe(VPValue *PredV) - : VPRecipeBase(VPPredInstPHISC), VPUser(PredV) {} + : VPRecipeBase(VPPredInstPHISC), VPUser(PredV) { + new VPValue(VPValue::VPValueSC, PredV->getUnderlyingValue(), 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 *D) { + return D->getVPDefID() == VPRecipeBase::VPPredInstPHISC; } /// Generates phi nodes for live-outs as needed to retain SSA form. @@ -1282,7 +1275,6 @@ public: /// TODO: We currently execute only per-part unless a specific instance is /// provided. class VPWidenMemoryInstructionRecipe : public VPRecipeBase, - public VPDef, public VPUser { Instruction &Ingredient; @@ -1312,8 +1304,8 @@ public: } /// 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 *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenMemoryInstructionSC; } /// Return the address accessed by this recipe. @@ -1347,21 +1339,16 @@ public: /// 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() : VPRecipeBase(VPWidenCanonicalIVSC) { + new VPValue(nullptr, this); + } + ~VPWidenCanonicalIVRecipe() override = default; - /// Return the VPValue representing the canonical vector induction variable of - /// the vector loop. - const VPValue *getVPValue() const { return &Val; } - VPValue *getVPValue() { return &Val; } - /// 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 *D) { + return D->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 index 609a56d3fa23..a1adccd5c75c 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanValue.h +++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h @@ -45,6 +45,7 @@ class VPWidenMemoryInstructionRecipe; class VPValue { friend class VPBuilder; friend class VPDef; + friend class VPInstruction; friend struct VPlanTransforms; friend class VPBasicBlock; friend class VPInterleavedAccessInfo; @@ -236,7 +237,7 @@ public: } /// 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); }; /// This class augments a recipe with a set of VPValues defined by the recipe. @@ -247,6 +248,9 @@ public: class VPDef { friend class VPValue; + /// Subclass identifier (for isa/dyn_cast). + const unsigned char SubclassID; + /// The VPValues defined by this VPDef. TinyPtrVector DefinedValues; @@ -269,6 +273,30 @@ class VPDef { } 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 + }; + + VPDef(const unsigned char SC) : SubclassID(SC) {} + virtual ~VPDef() { for (VPValue *D : make_early_inc_range(DefinedValues)) { assert(D->Def == this && @@ -295,6 +323,11 @@ public: /// Returns the number of values defined by the VPDef. 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 index 4864d52ad01e..c0230774bd90 100644 --- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp @@ -365,7 +365,7 @@ TEST(VPRecipeTest, CastVPInstructionToVPUser) { EXPECT_TRUE(isa(&Recipe)); VPRecipeBase *BaseR = &Recipe; EXPECT_TRUE(isa(BaseR)); - EXPECT_EQ(&Recipe, BaseR->toVPUser()); + EXPECT_EQ(&Recipe, BaseR); } TEST(VPRecipeTest, CastVPWidenRecipeToVPUser) { @@ -383,11 +383,11 @@ TEST(VPRecipeTest, CastVPWidenRecipeToVPUser) { EXPECT_TRUE(isa(&WidenR)); VPRecipeBase *WidenRBase = &WidenR; EXPECT_TRUE(isa(WidenRBase)); - EXPECT_EQ(&WidenR, WidenRBase->toVPUser()); + EXPECT_EQ(&WidenR, WidenRBase); delete AI; } -TEST(VPRecipeTest, CastVPWidenCallRecipeToVPUser) { +TEST(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPDef) { LLVMContext C; IntegerType *Int32 = IntegerType::get(C, 32); @@ -402,11 +402,16 @@ TEST(VPRecipeTest, CastVPWidenCallRecipeToVPUser) { EXPECT_TRUE(isa(&Recipe)); VPRecipeBase *BaseR = &Recipe; EXPECT_TRUE(isa(BaseR)); - EXPECT_EQ(&Recipe, BaseR->toVPUser()); + EXPECT_EQ(&Recipe, BaseR); + + VPValue *VPV = &Recipe; + EXPECT_TRUE(isa(VPV->getDef())); + EXPECT_EQ(&Recipe, dyn_cast(VPV->getDef())); + delete Call; } -TEST(VPRecipeTest, CastVPWidenSelectRecipeToVPUser) { +TEST(VPRecipeTest, CastVPWidenSelectRecipeToVPUserAndVPDef) { LLVMContext C; IntegerType *Int1 = IntegerType::get(C, 1); @@ -425,11 +430,16 @@ TEST(VPRecipeTest, CastVPWidenSelectRecipeToVPUser) { EXPECT_TRUE(isa(&WidenSelectR)); VPRecipeBase *BaseR = &WidenSelectR; EXPECT_TRUE(isa(BaseR)); - EXPECT_EQ(&WidenSelectR, BaseR->toVPUser()); + EXPECT_EQ(&WidenSelectR, BaseR); + + VPValue *VPV = &WidenSelectR; + EXPECT_TRUE(isa(VPV->getDef())); + EXPECT_EQ(&WidenSelectR, dyn_cast(VPV->getDef())); + delete SelectI; } -TEST(VPRecipeTest, CastVPWidenGEPRecipeToVPUser) { +TEST(VPRecipeTest, CastVPWidenGEPRecipeToVPUserAndVPDef) { LLVMContext C; IntegerType *Int32 = IntegerType::get(C, 32); @@ -445,7 +455,12 @@ TEST(VPRecipeTest, CastVPWidenGEPRecipeToVPUser) { EXPECT_TRUE(isa(&Recipe)); VPRecipeBase *BaseR = &Recipe; EXPECT_TRUE(isa(BaseR)); - EXPECT_EQ(&Recipe, BaseR->toVPUser()); + EXPECT_EQ(&Recipe, BaseR); + + VPValue *VPV = &Recipe; + EXPECT_TRUE(isa(VPV->getDef())); + EXPECT_EQ(&Recipe, dyn_cast(VPV->getDef())); + delete GEP; } @@ -476,7 +491,7 @@ TEST(VPRecipeTest, CastVPInterleaveRecipeToVPUser) { EXPECT_TRUE(isa(&Recipe)); VPRecipeBase *BaseR = &Recipe; EXPECT_TRUE(isa(BaseR)); - EXPECT_EQ(&Recipe, BaseR->toVPUser()); + EXPECT_EQ(&Recipe, BaseR); } TEST(VPRecipeTest, CastVPReplicateRecipeToVPUser) { @@ -503,10 +518,10 @@ TEST(VPRecipeTest, CastVPBranchOnMaskRecipeToVPUser) { EXPECT_TRUE(isa(&Recipe)); VPRecipeBase *BaseR = &Recipe; EXPECT_TRUE(isa(BaseR)); - EXPECT_EQ(&Recipe, BaseR->toVPUser()); + EXPECT_EQ(&Recipe, BaseR); } -TEST(VPRecipeTest, CastVPWidenMemoryInstructionRecipeToVPUser) { +TEST(VPRecipeTest, CastVPWidenMemoryInstructionRecipeToVPUserAndVPDef) { LLVMContext C; IntegerType *Int32 = IntegerType::get(C, 32); @@ -519,7 +534,12 @@ TEST(VPRecipeTest, CastVPWidenMemoryInstructionRecipeToVPUser) { EXPECT_TRUE(isa(&Recipe)); VPRecipeBase *BaseR = &Recipe; EXPECT_TRUE(isa(BaseR)); - EXPECT_EQ(&Recipe, BaseR->toVPUser()); + EXPECT_EQ(&Recipe, BaseR); + + VPValue *VPV = Recipe.getVPValue(); + EXPECT_TRUE(isa(VPV->getDef())); + EXPECT_EQ(&Recipe, dyn_cast(VPV->getDef())); + delete Load; } @@ -536,11 +556,16 @@ TEST(VPRecipeTest, CastVPReductionRecipeToVPUser) { EXPECT_TRUE(isa(BaseR)); } -struct VPDoubleValueDef : public VPUser, public VPDef { - VPDoubleValueDef(ArrayRef Operands) : VPUser(Operands), VPDef() { +struct VPDoubleValueDef : public VPRecipeBase, public VPUser { + VPDoubleValueDef(ArrayRef Operands) + : VPRecipeBase(99), VPUser(Operands) { new VPValue(nullptr, this); new VPValue(nullptr, this); } + + void execute(struct VPTransformState &State) override{}; + void print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const override {} }; TEST(VPDoubleValueDefTest, traverseUseLists) {