-
Notifications
You must be signed in to change notification settings - Fork 12.2k
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
[VPlan] Split VPWidenMemoryInstructionRecipe (NFCI). #87411
Changes from 7 commits
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 | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -8095,7 +8095,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)) && | ||||||||||||||||||||
|
@@ -8140,12 +8140,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 | ||||||||||||||||||||
|
@@ -8780,13 +8780,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()); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -9464,27 +9463,19 @@ static Instruction *lowerLoadUsingVectorIntrinsics(IRBuilderBase &Builder, | |||||||||||||||||||
return Call; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
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"); | ||||||||||||||||||||
auto *LI = cast<LoadInst>(&Ingredient); | ||||||||||||||||||||
|
||||||||||||||||||||
Type *ScalarDataTy = getLoadStoreType(&Ingredient); | ||||||||||||||||||||
|
||||||||||||||||||||
auto *DataTy = VectorType::get(ScalarDataTy, State.VF); | ||||||||||||||||||||
const Align Alignment = getLoadStoreAlignment(&Ingredient); | ||||||||||||||||||||
bool CreateGatherScatter = !isConsecutive(); | ||||||||||||||||||||
bool CreateGather = !isConsecutive(); | ||||||||||||||||||||
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. Kept as is for now, as |
||||||||||||||||||||
|
||||||||||||||||||||
auto &Builder = State.Builder; | ||||||||||||||||||||
InnerLoopVectorizer::VectorParts BlockInMaskParts(State.UF); | ||||||||||||||||||||
bool isMaskRequired = getMask(); | ||||||||||||||||||||
if (isMaskRequired) { | ||||||||||||||||||||
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. Now that loads and stores are handled separately, it makes sense for each to get its mask while taking care of each part, instead of preparing BlockInMaskParts, and do so once for all EVL/gather/consecutive cases. I.e.,
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. Updated, 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) { | ||||||||||||||||||||
|
@@ -9495,56 +9486,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); | ||||||||||||||||||||
// TODO: split this into several classes for better design. | ||||||||||||||||||||
if (State.EVL) { | ||||||||||||||||||||
assert(State.UF == 1 && "Expected only UF == 1 when vectorizing with " | ||||||||||||||||||||
"explicit vector length."); | ||||||||||||||||||||
assert(cast<VPInstruction>(State.EVL)->getOpcode() == | ||||||||||||||||||||
VPInstruction::ExplicitVectorLength && | ||||||||||||||||||||
"EVL must be VPInstruction::ExplicitVectorLength."); | ||||||||||||||||||||
Value *EVL = State.get(State.EVL, VPIteration(0, 0)); | ||||||||||||||||||||
// If EVL is not nullptr, then EVL must be a valid value set during plan | ||||||||||||||||||||
// creation, possibly default value = whole vector register length. EVL | ||||||||||||||||||||
// is created only if TTI prefers predicated vectorization, thus if EVL | ||||||||||||||||||||
// is not nullptr it also implies preference for predicated | ||||||||||||||||||||
// vectorization. | ||||||||||||||||||||
// FIXME: Support reverse store after vp_reverse is added. | ||||||||||||||||||||
Value *MaskPart = isMaskRequired ? BlockInMaskParts[Part] : nullptr; | ||||||||||||||||||||
NewSI = lowerStoreUsingVectorIntrinsics( | ||||||||||||||||||||
Builder, State.get(getAddr(), Part, !CreateGatherScatter), | ||||||||||||||||||||
StoredVal, CreateGatherScatter, MaskPart, EVL, Alignment); | ||||||||||||||||||||
} else 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()); | ||||||||||||||||||||
|
@@ -9564,19 +9505,19 @@ void VPWidenMemoryInstructionRecipe::execute(VPTransformState &State) { | |||||||||||||||||||
// is not nullptr it also implies preference for predicated | ||||||||||||||||||||
// vectorization. | ||||||||||||||||||||
// FIXME: Support reverse loading after vp_reverse is added. | ||||||||||||||||||||
Value *MaskPart = isMaskRequired ? BlockInMaskParts[Part] : nullptr; | ||||||||||||||||||||
Value *MaskPart = IsMaskRequired ? BlockInMaskParts[Part] : nullptr; | ||||||||||||||||||||
NewLI = lowerLoadUsingVectorIntrinsics( | ||||||||||||||||||||
Builder, DataTy, State.get(getAddr(), Part, !CreateGatherScatter), | ||||||||||||||||||||
CreateGatherScatter, MaskPart, EVL, Alignment); | ||||||||||||||||||||
} else if (CreateGatherScatter) { | ||||||||||||||||||||
Value *MaskPart = isMaskRequired ? BlockInMaskParts[Part] : nullptr; | ||||||||||||||||||||
Builder, DataTy, State.get(getAddr(), Part, !CreateGather), | ||||||||||||||||||||
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. Kept as is for now, as |
||||||||||||||||||||
CreateGather, MaskPart, EVL, Alignment); | ||||||||||||||||||||
} else if (CreateGather) { | ||||||||||||||||||||
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. Kept as is for now, as |
||||||||||||||||||||
Value *MaskPart = IsMaskRequired ? BlockInMaskParts[Part] : nullptr; | ||||||||||||||||||||
Value *VectorGep = State.get(getAddr(), Part); | ||||||||||||||||||||
NewLI = Builder.CreateMaskedGather(DataTy, VectorGep, Alignment, MaskPart, | ||||||||||||||||||||
nullptr, "wide.masked.gather"); | ||||||||||||||||||||
State.addMetadata(NewLI, LI); | ||||||||||||||||||||
} else { | ||||||||||||||||||||
auto *VecPtr = State.get(getAddr(), Part, /*IsScalar*/ true); | ||||||||||||||||||||
if (isMaskRequired) | ||||||||||||||||||||
if (IsMaskRequired) | ||||||||||||||||||||
NewLI = Builder.CreateMaskedLoad( | ||||||||||||||||||||
DataTy, VecPtr, Alignment, BlockInMaskParts[Part], | ||||||||||||||||||||
PoisonValue::get(DataTy), "wide.masked.load"); | ||||||||||||||||||||
|
@@ -9590,7 +9531,75 @@ 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) { | ||||||||||||||||||||
auto *SI = cast<StoreInst>(&Ingredient); | ||||||||||||||||||||
|
||||||||||||||||||||
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! |
||||||||||||||||||||
bool CreateScatter = !isConsecutive(); | ||||||||||||||||||||
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. Kept as is for now, as |
||||||||||||||||||||
const Align Alignment = getLoadStoreAlignment(&Ingredient); | ||||||||||||||||||||
|
||||||||||||||||||||
auto &Builder = State.Builder; | ||||||||||||||||||||
InnerLoopVectorizer::VectorParts BlockInMaskParts(State.UF); | ||||||||||||||||||||
bool IsMaskRequired = getMask(); | ||||||||||||||||||||
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! |
||||||||||||||||||||
// TODO: split this into several classes for better design. | ||||||||||||||||||||
if (State.EVL) { | ||||||||||||||||||||
assert(State.UF == 1 && "Expected only UF == 1 when vectorizing with " | ||||||||||||||||||||
"explicit vector length."); | ||||||||||||||||||||
assert(cast<VPInstruction>(State.EVL)->getOpcode() == | ||||||||||||||||||||
VPInstruction::ExplicitVectorLength && | ||||||||||||||||||||
"EVL must be VPInstruction::ExplicitVectorLength."); | ||||||||||||||||||||
Value *EVL = State.get(State.EVL, VPIteration(0, 0)); | ||||||||||||||||||||
// If EVL is not nullptr, then EVL must be a valid value set during plan | ||||||||||||||||||||
// creation, possibly default value = whole vector register length. EVL | ||||||||||||||||||||
// is created only if TTI prefers predicated vectorization, thus if EVL | ||||||||||||||||||||
// is not nullptr it also implies preference for predicated | ||||||||||||||||||||
// vectorization. | ||||||||||||||||||||
// FIXME: Support reverse store after vp_reverse is added. | ||||||||||||||||||||
Value *MaskPart = IsMaskRequired ? BlockInMaskParts[Part] : nullptr; | ||||||||||||||||||||
NewSI = lowerStoreUsingVectorIntrinsics( | ||||||||||||||||||||
Builder, State.get(getAddr(), Part, !CreateScatter), 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
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. Kept as is for now, as CreateScatter seems slightly more descriptive w.r.t. how it is used |
||||||||||||||||||||
CreateScatter, MaskPart, EVL, Alignment); | ||||||||||||||||||||
} else if (CreateScatter) { | ||||||||||||||||||||
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. Kept as is for now, as CreateScatter seems slightly more descriptive w.r.t. how it is used |
||||||||||||||||||||
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); | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
|
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!