-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[VPlan] Split VPWidenMemoryInstructionRecipe (NFCI). #87411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
fd59651
132a5da
09de83e
e5cba93
be4033c
ffa600c
fe09e81
ea170df
7106160
792be89
06285b9
3d15115
2b96fc5
dd5f1f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -8028,7 +8028,7 @@ void VPRecipeBuilder::createBlockInMask(BasicBlock *BB) { | |||||||||||||||||||
BlockMaskCache[BB] = BlockMask; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
VPWidenMemoryInstructionRecipe * | ||||||||||||||||||||
VPWidenMemoryRecipe * | ||||||||||||||||||||
VPRecipeBuilder::tryToWidenMemory(Instruction *I, ArrayRef<VPValue *> Operands, | ||||||||||||||||||||
VFRange &Range) { | ||||||||||||||||||||
assert((isa<LoadInst>(I) || isa<StoreInst>(I)) && | ||||||||||||||||||||
|
@@ -8073,12 +8073,12 @@ VPRecipeBuilder::tryToWidenMemory(Instruction *I, ArrayRef<VPValue *> Operands, | |||||||||||||||||||
Ptr = VectorPtr; | ||||||||||||||||||||
} | ||||||||||||||||||||
if (LoadInst *Load = dyn_cast<LoadInst>(I)) | ||||||||||||||||||||
return new VPWidenMemoryInstructionRecipe(*Load, Ptr, Mask, Consecutive, | ||||||||||||||||||||
Reverse, I->getDebugLoc()); | ||||||||||||||||||||
return new VPWidenLoadRecipe(*Load, Ptr, Mask, Consecutive, Reverse, | ||||||||||||||||||||
I->getDebugLoc()); | ||||||||||||||||||||
|
||||||||||||||||||||
StoreInst *Store = cast<StoreInst>(I); | ||||||||||||||||||||
return new VPWidenMemoryInstructionRecipe( | ||||||||||||||||||||
*Store, Ptr, Operands[0], Mask, Consecutive, Reverse, I->getDebugLoc()); | ||||||||||||||||||||
return new VPWidenStoreRecipe(*Store, Operands[0], Ptr, Mask, Consecutive, | ||||||||||||||||||||
Reverse, I->getDebugLoc()); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
/// Creates a VPWidenIntOrFpInductionRecpipe for \p Phi. If needed, it will also | ||||||||||||||||||||
|
@@ -8710,13 +8710,12 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) { | |||||||||||||||||||
// for this VPlan, replace the Recipes widening its memory instructions with a | ||||||||||||||||||||
// single VPInterleaveRecipe at its insertion point. | ||||||||||||||||||||
for (const auto *IG : InterleaveGroups) { | ||||||||||||||||||||
auto *Recipe = cast<VPWidenMemoryInstructionRecipe>( | ||||||||||||||||||||
RecipeBuilder.getRecipe(IG->getInsertPos())); | ||||||||||||||||||||
auto *Recipe = | ||||||||||||||||||||
cast<VPWidenMemoryRecipe>(RecipeBuilder.getRecipe(IG->getInsertPos())); | ||||||||||||||||||||
SmallVector<VPValue *, 4> StoredValues; | ||||||||||||||||||||
for (unsigned i = 0; i < IG->getFactor(); ++i) | ||||||||||||||||||||
if (auto *SI = dyn_cast_or_null<StoreInst>(IG->getMember(i))) { | ||||||||||||||||||||
auto *StoreR = | ||||||||||||||||||||
cast<VPWidenMemoryInstructionRecipe>(RecipeBuilder.getRecipe(SI)); | ||||||||||||||||||||
auto *StoreR = cast<VPWidenStoreRecipe>(RecipeBuilder.getRecipe(SI)); | ||||||||||||||||||||
StoredValues.push_back(StoreR->getStoredValue()); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -9307,16 +9306,9 @@ void VPReplicateRecipe::execute(VPTransformState &State) { | |||||||||||||||||||
State.ILV->scalarizeInstruction(UI, this, VPIteration(Part, Lane), State); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
void VPWidenMemoryInstructionRecipe::execute(VPTransformState &State) { | ||||||||||||||||||||
VPValue *StoredValue = isStore() ? getStoredValue() : nullptr; | ||||||||||||||||||||
|
||||||||||||||||||||
void VPWidenLoadRecipe::execute(VPTransformState &State) { | ||||||||||||||||||||
// Attempt to issue a wide load. | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit: redundant? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed, thanks |
||||||||||||||||||||
LoadInst *LI = dyn_cast<LoadInst>(&Ingredient); | ||||||||||||||||||||
StoreInst *SI = dyn_cast<StoreInst>(&Ingredient); | ||||||||||||||||||||
|
||||||||||||||||||||
assert((LI || SI) && "Invalid Load/Store instruction"); | ||||||||||||||||||||
assert((!SI || StoredValue) && "No stored value provided for widened store"); | ||||||||||||||||||||
assert((!LI || !StoredValue) && "Stored value provided for widened load"); | ||||||||||||||||||||
LoadInst *LI = cast<LoadInst>(&Ingredient); | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, thanks! |
||||||||||||||||||||
|
||||||||||||||||||||
Type *ScalarDataTy = getLoadStoreType(&Ingredient); | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -9338,38 +9330,6 @@ void VPWidenMemoryInstructionRecipe::execute(VPTransformState &State) { | |||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// Handle Stores: | ||||||||||||||||||||
if (SI) { | ||||||||||||||||||||
State.setDebugLocFrom(getDebugLoc()); | ||||||||||||||||||||
|
||||||||||||||||||||
for (unsigned Part = 0; Part < State.UF; ++Part) { | ||||||||||||||||||||
Instruction *NewSI = nullptr; | ||||||||||||||||||||
Value *StoredVal = State.get(StoredValue, Part); | ||||||||||||||||||||
if (CreateGatherScatter) { | ||||||||||||||||||||
Value *MaskPart = isMaskRequired ? BlockInMaskParts[Part] : nullptr; | ||||||||||||||||||||
Value *VectorGep = State.get(getAddr(), Part); | ||||||||||||||||||||
NewSI = Builder.CreateMaskedScatter(StoredVal, VectorGep, Alignment, | ||||||||||||||||||||
MaskPart); | ||||||||||||||||||||
} else { | ||||||||||||||||||||
if (isReverse()) { | ||||||||||||||||||||
// If we store to reverse consecutive memory locations, then we need | ||||||||||||||||||||
// to reverse the order of elements in the stored value. | ||||||||||||||||||||
StoredVal = Builder.CreateVectorReverse(StoredVal, "reverse"); | ||||||||||||||||||||
// We don't want to update the value in the map as it might be used in | ||||||||||||||||||||
// another expression. So don't call resetVectorValue(StoredVal). | ||||||||||||||||||||
} | ||||||||||||||||||||
auto *VecPtr = State.get(getAddr(), Part, /*IsScalar*/ true); | ||||||||||||||||||||
if (isMaskRequired) | ||||||||||||||||||||
NewSI = Builder.CreateMaskedStore(StoredVal, VecPtr, Alignment, | ||||||||||||||||||||
BlockInMaskParts[Part]); | ||||||||||||||||||||
else | ||||||||||||||||||||
NewSI = Builder.CreateAlignedStore(StoredVal, VecPtr, Alignment); | ||||||||||||||||||||
} | ||||||||||||||||||||
State.addMetadata(NewSI, SI); | ||||||||||||||||||||
} | ||||||||||||||||||||
return; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// Handle loads. | ||||||||||||||||||||
assert(LI && "Must have a load instruction"); | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Only loads are handled, and LI is asserted to be non-null by the non-dynamic cast. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed, thanks! |
||||||||||||||||||||
State.setDebugLocFrom(getDebugLoc()); | ||||||||||||||||||||
|
@@ -9397,7 +9357,59 @@ void VPWidenMemoryInstructionRecipe::execute(VPTransformState &State) { | |||||||||||||||||||
NewLI = Builder.CreateVectorReverse(NewLI, "reverse"); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
State.set(getVPSingleValue(), NewLI, Part); | ||||||||||||||||||||
State.set(this, NewLI, Part); | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
void VPWidenStoreRecipe::execute(VPTransformState &State) { | ||||||||||||||||||||
VPValue *StoredValue = getStoredValue(); | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit: clarify the distinction between Stored Value and Stored VPValue, as in Mask and VPMask. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, thanks! |
||||||||||||||||||||
|
||||||||||||||||||||
// Attempt to issue a wide load. | ||||||||||||||||||||
StoreInst *SI = cast<StoreInst>(&Ingredient); | ||||||||||||||||||||
|
||||||||||||||||||||
const Align Alignment = getLoadStoreAlignment(&Ingredient); | ||||||||||||||||||||
bool CreateGatherScatter = !isConsecutive(); | ||||||||||||||||||||
|
||||||||||||||||||||
auto &Builder = State.Builder; | ||||||||||||||||||||
InnerLoopVectorizer::VectorParts BlockInMaskParts(State.UF); | ||||||||||||||||||||
bool isMaskRequired = getMask(); | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, thanks! |
||||||||||||||||||||
if (isMaskRequired) { | ||||||||||||||||||||
// Mask reversal is only needed for non-all-one (null) masks, as reverse of | ||||||||||||||||||||
// a null all-one mask is a null mask. | ||||||||||||||||||||
for (unsigned Part = 0; Part < State.UF; ++Part) { | ||||||||||||||||||||
Value *Mask = State.get(getMask(), Part); | ||||||||||||||||||||
if (isReverse()) | ||||||||||||||||||||
Mask = Builder.CreateVectorReverse(Mask, "reverse"); | ||||||||||||||||||||
BlockInMaskParts[Part] = Mask; | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
State.setDebugLocFrom(getDebugLoc()); | ||||||||||||||||||||
|
||||||||||||||||||||
for (unsigned Part = 0; Part < State.UF; ++Part) { | ||||||||||||||||||||
Instruction *NewSI = nullptr; | ||||||||||||||||||||
Value *StoredVal = State.get(StoredValue, Part); | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hoisted, thanks! |
||||||||||||||||||||
if (CreateGatherScatter) { | ||||||||||||||||||||
Value *MaskPart = isMaskRequired ? BlockInMaskParts[Part] : nullptr; | ||||||||||||||||||||
Value *VectorGep = State.get(getAddr(), Part); | ||||||||||||||||||||
NewSI = Builder.CreateMaskedScatter(StoredVal, VectorGep, Alignment, | ||||||||||||||||||||
MaskPart); | ||||||||||||||||||||
} else { | ||||||||||||||||||||
if (isReverse()) { | ||||||||||||||||||||
// If we store to reverse consecutive memory locations, then we need | ||||||||||||||||||||
// to reverse the order of elements in the stored value. | ||||||||||||||||||||
StoredVal = Builder.CreateVectorReverse(StoredVal, "reverse"); | ||||||||||||||||||||
// We don't want to update the value in the map as it might be used in | ||||||||||||||||||||
// another expression. So don't call resetVectorValue(StoredVal). | ||||||||||||||||||||
} | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit: better fix StoredVal above, when set. Can assert that reverse implies !State.EVL. The assert that reverse implies !CreateScatter == isConsecutive is already there. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hoisted, thanks! |
||||||||||||||||||||
auto *VecPtr = State.get(getAddr(), Part, /*IsScalar*/ true); | ||||||||||||||||||||
if (isMaskRequired) | ||||||||||||||||||||
NewSI = Builder.CreateMaskedStore(StoredVal, VecPtr, Alignment, | ||||||||||||||||||||
BlockInMaskParts[Part]); | ||||||||||||||||||||
else | ||||||||||||||||||||
NewSI = Builder.CreateAlignedStore(StoredVal, VecPtr, Alignment); | ||||||||||||||||||||
} | ||||||||||||||||||||
State.addMetadata(NewSI, SI); | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -870,7 +870,8 @@ class VPSingleDefRecipe : public VPRecipeBase, public VPValue { | |||||
return true; | ||||||
case VPRecipeBase::VPInterleaveSC: | ||||||
case VPRecipeBase::VPBranchOnMaskSC: | ||||||
case VPRecipeBase::VPWidenMemoryInstructionSC: | ||||||
case VPRecipeBase::VPWidenLoadSC: | ||||||
case VPRecipeBase::VPWidenStoreSC: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, the TODO below suggests that Loads should (also) be considered single def. Should VPWidenLoadRecipe inherit from both VPWidenMemoryRecipe and VPSingleDefRecipe? (Deserves a separate patch, but worth thinking when introducing the class hierarchy here.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, unfortunately it will require some extra work, as at the moment both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another alternative may be to also consider VPWidenStoreRecipe as a Single Def recipe, with a singleton "void" Def that has no uses. Akin to LLVM. I.e., VPSingle[OrNo]DefRecipe. |
||||||
// TODO: Widened stores don't define a value, but widened loads do. Split | ||||||
// the recipes to be able to make widened loads VPSingleDefRecipes. | ||||||
return false; | ||||||
|
@@ -2273,7 +2274,8 @@ class VPPredInstPHIRecipe : public VPSingleDefRecipe { | |||||
/// - For store: Address, stored value, optional mask | ||||||
/// TODO: We currently execute only per-part unless a specific instance is | ||||||
/// provided. | ||||||
class VPWidenMemoryInstructionRecipe : public VPRecipeBase { | ||||||
class VPWidenMemoryRecipe : public VPRecipeBase { | ||||||
protected: | ||||||
Instruction &Ingredient; | ||||||
|
||||||
// Whether the loaded-from / stored-to addresses are consecutive. | ||||||
|
@@ -2293,42 +2295,23 @@ class VPWidenMemoryInstructionRecipe : public VPRecipeBase { | |||||
} | ||||||
|
||||||
public: | ||||||
VPWidenMemoryInstructionRecipe(LoadInst &Load, VPValue *Addr, VPValue *Mask, | ||||||
bool Consecutive, bool Reverse, DebugLoc DL) | ||||||
: VPRecipeBase(VPDef::VPWidenMemoryInstructionSC, {Addr}, DL), | ||||||
Ingredient(Load), Consecutive(Consecutive), Reverse(Reverse) { | ||||||
VPWidenMemoryRecipe(const char unsigned SC, Instruction &I, | ||||||
std::initializer_list<VPValue *> Operands, | ||||||
bool Consecutive, bool Reverse, DebugLoc DL) | ||||||
: VPRecipeBase(SC, Operands, DL), Ingredient(I), Consecutive(Consecutive), | ||||||
Reverse(Reverse) { | ||||||
assert((Consecutive || !Reverse) && "Reverse implies consecutive"); | ||||||
new VPValue(this, &Load); | ||||||
setMask(Mask); | ||||||
} | ||||||
|
||||||
VPWidenMemoryInstructionRecipe(StoreInst &Store, VPValue *Addr, | ||||||
VPValue *StoredValue, VPValue *Mask, | ||||||
bool Consecutive, bool Reverse, DebugLoc DL) | ||||||
: VPRecipeBase(VPDef::VPWidenMemoryInstructionSC, {Addr, StoredValue}, | ||||||
DL), | ||||||
Ingredient(Store), Consecutive(Consecutive), Reverse(Reverse) { | ||||||
assert((Consecutive || !Reverse) && "Reverse implies consecutive"); | ||||||
setMask(Mask); | ||||||
} | ||||||
VPRecipeBase *clone() override = 0; | ||||||
|
||||||
VPRecipeBase *clone() override { | ||||||
if (isStore()) | ||||||
return new VPWidenMemoryInstructionRecipe( | ||||||
cast<StoreInst>(Ingredient), getAddr(), getStoredValue(), getMask(), | ||||||
Consecutive, Reverse, getDebugLoc()); | ||||||
|
||||||
return new VPWidenMemoryInstructionRecipe(cast<LoadInst>(Ingredient), | ||||||
getAddr(), getMask(), Consecutive, | ||||||
Reverse, getDebugLoc()); | ||||||
static inline bool classof(const VPRecipeBase *R) { | ||||||
return R->getVPDefID() == VPRecipeBase::VPWidenStoreSC || | ||||||
R->getVPDefID() == VPRecipeBase::VPWidenLoadSC; | ||||||
} | ||||||
|
||||||
VP_CLASSOF_IMPL(VPDef::VPWidenMemoryInstructionSC) | ||||||
|
||||||
/// Return the address accessed by this recipe. | ||||||
VPValue *getAddr() const { | ||||||
return getOperand(0); // Address is the 1st, mandatory operand. | ||||||
} | ||||||
virtual VPValue *getAddr() const = 0; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you really need to make it virtual? I think you can just remove it from the base class There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are callers that need to get the address of any WidenMemoryRecipe (e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better to use static isa/dyn_cast sequences where possible instead of virtual functions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough, replaced with an implementation using |
||||||
|
||||||
/// Return the mask used by this recipe. Note that a full mask is represented | ||||||
/// by a nullptr. | ||||||
|
@@ -2340,19 +2323,44 @@ class VPWidenMemoryInstructionRecipe : public VPRecipeBase { | |||||
/// Returns true if this recipe is a store. | ||||||
bool isStore() const { return isa<StoreInst>(Ingredient); } | ||||||
|
||||||
/// Return the address accessed by this recipe. | ||||||
VPValue *getStoredValue() const { | ||||||
assert(isStore() && "Stored value only available for store instructions"); | ||||||
return getOperand(1); // Stored value is the 2nd, mandatory operand. | ||||||
} | ||||||
|
||||||
// Return whether the loaded-from / stored-to addresses are consecutive. | ||||||
bool isConsecutive() const { return Consecutive; } | ||||||
|
||||||
// Return whether the consecutive loaded/stored addresses are in reverse | ||||||
// order. | ||||||
bool isReverse() const { return Reverse; } | ||||||
|
||||||
/// Generate the wide load/store. | ||||||
void execute(VPTransformState &State) override = 0; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you really need to make it pure virtual or just enough to have execute function in each implementation? And here just make it llvm_unreachable? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replaced with |
||||||
|
||||||
Instruction &getIngredient() const { return Ingredient; } | ||||||
}; | ||||||
|
||||||
struct VPWidenLoadRecipe : public VPWidenMemoryRecipe, public VPValue { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. final? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, thanks! |
||||||
VPWidenLoadRecipe(LoadInst &Load, VPValue *Addr, VPValue *Mask, | ||||||
bool Consecutive, bool Reverse, DebugLoc DL) | ||||||
: VPWidenMemoryRecipe(VPDef::VPWidenLoadSC, Load, {Addr}, Consecutive, | ||||||
Reverse, DL), | ||||||
VPValue(this, &Load) { | ||||||
assert((Consecutive || !Reverse) && "Reverse implies consecutive"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: suffice to assert that reverse implies consecutive once, in the WidenMemory base class, where they are held. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed here, thanks! |
||||||
setMask(Mask); | ||||||
} | ||||||
|
||||||
VPRecipeBase *clone() override { | ||||||
return new VPWidenLoadRecipe(cast<LoadInst>(Ingredient), getAddr(), | ||||||
getMask(), Consecutive, Reverse, | ||||||
getDebugLoc()); | ||||||
} | ||||||
|
||||||
static inline bool classof(const VPRecipeBase *R) { | ||||||
return R->getVPDefID() == VPRecipeBase::VPWidenLoadSC; | ||||||
} | ||||||
|
||||||
/// Return the address accessed by this recipe. | ||||||
VPValue *getAddr() const override { | ||||||
return getOperand(0); // Address is the 1st, mandatory operand. | ||||||
} | ||||||
|
||||||
/// Generate the wide load/store. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, thanks! |
||||||
void execute(VPTransformState &State) override; | ||||||
|
||||||
|
@@ -2370,13 +2378,55 @@ class VPWidenMemoryInstructionRecipe : public VPRecipeBase { | |||||
// Widened, consecutive memory operations only demand the first lane of | ||||||
// their address, unless the same operand is also stored. That latter can | ||||||
// happen with opaque pointers. | ||||||
return Op == getAddr() && isConsecutive() && | ||||||
(!isStore() || Op != getStoredValue()); | ||||||
return Op == getAddr() && isConsecutive(); | ||||||
} | ||||||
|
||||||
Instruction &getIngredient() const { return Ingredient; } | ||||||
}; | ||||||
|
||||||
struct VPWidenStoreRecipe : public VPWidenMemoryRecipe { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. final? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, thanks! |
||||||
VPWidenStoreRecipe(StoreInst &Store, VPValue *StoredVal, VPValue *Addr, | ||||||
VPValue *Mask, bool Consecutive, bool Reverse, DebugLoc DL) | ||||||
: VPWidenMemoryRecipe(VPDef::VPWidenStoreSC, Store, {StoredVal, Addr}, | ||||||
Consecutive, Reverse, DL) { | ||||||
assert((Consecutive || !Reverse) && "Reverse implies consecutive"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: suffice to assert that reverse implies consecutive in the WidenMemory base class, where they are held. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed here, thanks! |
||||||
setMask(Mask); | ||||||
} | ||||||
|
||||||
VPRecipeBase *clone() override { | ||||||
return new VPWidenStoreRecipe(cast<StoreInst>(Ingredient), getStoredValue(), | ||||||
getAddr(), getMask(), Consecutive, Reverse, | ||||||
getDebugLoc()); | ||||||
} | ||||||
|
||||||
static inline bool classof(const VPRecipeBase *R) { | ||||||
return R->getVPDefID() == VPRecipeBase::VPWidenStoreSC; | ||||||
} | ||||||
|
||||||
/// Return the address accessed by this recipe. | ||||||
VPValue *getAddr() const override { return getOperand(1); } | ||||||
|
||||||
/// Return the address accessed by this recipe. | ||||||
VPValue *getStoredValue() const { return getOperand(0); } | ||||||
|
||||||
/// Generate the wide load/store. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, thanks! |
||||||
void execute(VPTransformState &State) override; | ||||||
|
||||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | ||||||
/// Print the recipe. | ||||||
void print(raw_ostream &O, const Twine &Indent, | ||||||
VPSlotTracker &SlotTracker) const override; | ||||||
#endif | ||||||
|
||||||
/// Returns true if the recipe only uses the first lane of operand \p Op. | ||||||
bool onlyFirstLaneUsed(const VPValue *Op) const override { | ||||||
assert(is_contained(operands(), Op) && | ||||||
"Op must be an operand of the recipe"); | ||||||
|
||||||
// Widened, consecutive memory operations only demand the first lane of | ||||||
// their address, unless the same operand is also stored. That latter can | ||||||
// happen with opaque pointers. | ||||||
return Op == getAddr() && isConsecutive() && Op != getStoredValue(); | ||||||
} | ||||||
}; | ||||||
/// Recipe to expand a SCEV expression. | ||||||
class VPExpandSCEVRecipe : public VPSingleDefRecipe { | ||||||
const SCEV *Expr; | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: worth retaining the parameters in their order as operands? I.e., Ptr as first operand, before stored value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated, thanks!