-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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] Introduce recipes for VP loads and stores. #87816
Changes from all commits
4533d92
c8fafce
cb97949
2436232
43ede9c
cdb7061
4cfbcf0
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 |
---|---|---|
|
@@ -242,15 +242,6 @@ struct VPTransformState { | |
ElementCount VF; | ||
unsigned UF; | ||
|
||
/// If EVL (Explicit Vector Length) is not nullptr, then EVL must be a valid | ||
/// value set during plan transformation, possibly a 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. | ||
/// TODO: this is a temporarily solution, the EVL must be explicitly used by | ||
/// the recipes and must be removed here. | ||
VPValue *EVL = nullptr; | ||
|
||
/// Hold the indices to generate specific scalar instructions. Null indicates | ||
/// that all instances are to be generated, using either scalar or vector | ||
/// instructions. | ||
|
@@ -875,7 +866,9 @@ class VPSingleDefRecipe : public VPRecipeBase, public VPValue { | |
return true; | ||
case VPRecipeBase::VPInterleaveSC: | ||
case VPRecipeBase::VPBranchOnMaskSC: | ||
case VPRecipeBase::VPWidenLoadEVLSC: | ||
case VPRecipeBase::VPWidenLoadSC: | ||
case VPRecipeBase::VPWidenStoreEVLSC: | ||
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. Add the two VP variants? 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. Added, thanks! |
||
// TODO: Widened stores don't define a value, but widened loads do. Split | ||
// the recipes to be able to make widened loads VPSingleDefRecipes. | ||
|
@@ -2318,11 +2311,15 @@ class VPWidenMemoryRecipe : public VPRecipeBase { | |
} | ||
|
||
public: | ||
VPWidenMemoryRecipe *clone() override = 0; | ||
VPWidenMemoryRecipe *clone() override { | ||
llvm_unreachable("cloning not supported"); | ||
} | ||
|
||
static inline bool classof(const VPRecipeBase *R) { | ||
return R->getVPDefID() == VPDef::VPWidenLoadSC || | ||
R->getVPDefID() == VPDef::VPWidenStoreSC; | ||
return R->getVPDefID() == VPRecipeBase::VPWidenLoadSC || | ||
R->getVPDefID() == VPRecipeBase::VPWidenStoreSC || | ||
R->getVPDefID() == VPRecipeBase::VPWidenLoadEVLSC || | ||
R->getVPDefID() == VPRecipeBase::VPWidenStoreEVLSC; | ||
} | ||
|
||
static inline bool classof(const VPUser *U) { | ||
|
@@ -2390,13 +2387,48 @@ struct VPWidenLoadRecipe final : public VPWidenMemoryRecipe, public VPValue { | |
bool onlyFirstLaneUsed(const VPValue *Op) const override { | ||
assert(is_contained(operands(), Op) && | ||
"Op must be an operand of the recipe"); | ||
|
||
// Widened, consecutive loads operations only demand the first lane of | ||
// their address. | ||
return Op == getAddr() && isConsecutive(); | ||
} | ||
}; | ||
|
||
/// A recipe for widening load operations with vector-predication intrinsics, | ||
/// using the address to load from, the explicit vector length and an optional | ||
/// mask. | ||
struct VPWidenLoadEVLRecipe final : public VPWidenMemoryRecipe, public VPValue { | ||
VPWidenLoadEVLRecipe(VPWidenLoadRecipe *L, VPValue *EVL, VPValue *Mask) | ||
: VPWidenMemoryRecipe(VPDef::VPWidenLoadEVLSC, L->getIngredient(), | ||
{L->getAddr(), EVL}, L->isConsecutive(), false, | ||
L->getDebugLoc()), | ||
VPValue(this, &getIngredient()) { | ||
setMask(Mask); | ||
} | ||
|
||
VP_CLASSOF_IMPL(VPDef::VPWidenLoadEVLSC) | ||
|
||
/// Return the EVL operand. | ||
VPValue *getEVL() const { return getOperand(1); } | ||
|
||
/// Generate the wide load or gather. | ||
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 loads only demand the first lane of EVL and consecutive loads | ||
// only demand the first lane of their address. | ||
return Op == getEVL() || (Op == getAddr() && isConsecutive()); | ||
} | ||
}; | ||
|
||
/// A recipe for widening store operations, using the stored value, the address | ||
/// to store to and an optional mask. | ||
struct VPWidenStoreRecipe final : public VPWidenMemoryRecipe { | ||
|
@@ -2436,6 +2468,50 @@ struct VPWidenStoreRecipe final : public VPWidenMemoryRecipe { | |
return Op == getAddr() && isConsecutive() && Op != getStoredValue(); | ||
} | ||
}; | ||
|
||
/// A recipe for widening store operations with vector-predication intrinsics, | ||
/// using the value to store, the address to store to, the explicit vector | ||
/// length and an optional mask. | ||
struct VPWidenStoreEVLRecipe final : public VPWidenMemoryRecipe { | ||
VPWidenStoreEVLRecipe(VPWidenStoreRecipe *S, VPValue *EVL, VPValue *Mask) | ||
: VPWidenMemoryRecipe(VPDef::VPWidenStoreEVLSC, S->getIngredient(), | ||
{S->getAddr(), S->getStoredValue(), EVL}, | ||
S->isConsecutive(), false, S->getDebugLoc()) { | ||
setMask(Mask); | ||
} | ||
|
||
VP_CLASSOF_IMPL(VPDef::VPWidenStoreEVLSC) | ||
|
||
/// Return the address accessed by this recipe. | ||
VPValue *getStoredValue() const { return getOperand(1); } | ||
|
||
/// Return the EVL operand. | ||
VPValue *getEVL() const { return getOperand(2); } | ||
|
||
/// Generate the wide store or scatter. | ||
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"); | ||
if (Op == getEVL()) { | ||
assert(getStoredValue() != Op && "unexpected store of EVL"); | ||
return true; | ||
} | ||
// 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(); | ||
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. Note: unlike the address operand, the EVL operand (scalar by nature) cannot also be stored (vector by nature). Worth an assert? 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! |
||
} | ||
}; | ||
|
||
/// 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: could be simplified a bit, consistent with VPWidenVPLoadRecipe::execute()?
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!
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.
Thanks! The brackets could be removed.
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.
Kept the braces as there are multi-line statements (for which I think it is recommended to use braces)
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.
ok, but let the store case below be consistent with the load case here?